summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib')
-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/Parse/RAIIObjectsForParser.h447
-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
489 files changed, 79230 insertions, 42286 deletions
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/Parse/RAIIObjectsForParser.h b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h
deleted file mode 100644
index 36d87eb..0000000
--- a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h
+++ /dev/null
@@ -1,447 +0,0 @@
-//===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- 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 and implements the some simple RAII objects that are used
-// by the parser to manage bits in recursion.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
-#define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
-
-#include "clang/Parse/ParseDiagnostic.h"
-#include "clang/Parse/Parser.h"
-#include "clang/Sema/DelayedDiagnostic.h"
-#include "clang/Sema/Sema.h"
-
-namespace clang {
- // TODO: move ParsingClassDefinition here.
- // TODO: move TentativeParsingAction here.
-
- /// \brief A RAII object used to temporarily suppress access-like
- /// checking. Access-like checks are those associated with
- /// controlling the use of a declaration, like C++ access control
- /// errors and deprecation warnings. They are contextually
- /// dependent, in that they can only be resolved with full
- /// information about what's being declared. They are also
- /// suppressed in certain contexts, like the template arguments of
- /// an explicit instantiation. However, those suppression contexts
- /// cannot necessarily be fully determined in advance; for
- /// example, something starting like this:
- /// template <> class std::vector<A::PrivateType>
- /// might be the entirety of an explicit instantiation:
- /// template <> class std::vector<A::PrivateType>;
- /// or just an elaborated type specifier:
- /// template <> class std::vector<A::PrivateType> make_vector<>();
- /// Therefore this class collects all the diagnostics and permits
- /// them to be re-delayed in a new context.
- class SuppressAccessChecks {
- Sema &S;
- sema::DelayedDiagnosticPool DiagnosticPool;
- Sema::ParsingDeclState State;
- bool Active;
-
- public:
- /// Begin suppressing access-like checks
- SuppressAccessChecks(Parser &P, bool activate = true)
- : S(P.getActions()), DiagnosticPool(nullptr) {
- if (activate) {
- State = S.PushParsingDeclaration(DiagnosticPool);
- Active = true;
- } else {
- Active = false;
- }
- }
- SuppressAccessChecks(SuppressAccessChecks &&Other)
- : S(Other.S), DiagnosticPool(std::move(Other.DiagnosticPool)),
- State(Other.State), Active(Other.Active) {
- Other.Active = false;
- }
- void operator=(SuppressAccessChecks &&Other) = delete;
-
- void done() {
- assert(Active && "trying to end an inactive suppression");
- S.PopParsingDeclaration(State, nullptr);
- Active = false;
- }
-
- void redelay() {
- assert(!Active && "redelaying without having ended first");
- if (!DiagnosticPool.pool_empty())
- S.redelayDiagnostics(DiagnosticPool);
- assert(DiagnosticPool.pool_empty());
- }
-
- ~SuppressAccessChecks() {
- if (Active) done();
- }
- };
-
- /// \brief RAII object used to inform the actions that we're
- /// currently parsing a declaration. This is active when parsing a
- /// variable's initializer, but not when parsing the body of a
- /// class or function definition.
- class ParsingDeclRAIIObject {
- Sema &Actions;
- sema::DelayedDiagnosticPool DiagnosticPool;
- Sema::ParsingDeclState State;
- bool Popped;
-
- ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) = delete;
- void operator=(const ParsingDeclRAIIObject &) = delete;
-
- public:
- enum NoParent_t { NoParent };
- ParsingDeclRAIIObject(Parser &P, NoParent_t _)
- : Actions(P.getActions()), DiagnosticPool(nullptr) {
- push();
- }
-
- /// Creates a RAII object whose pool is optionally parented by another.
- ParsingDeclRAIIObject(Parser &P,
- const sema::DelayedDiagnosticPool *parentPool)
- : Actions(P.getActions()), DiagnosticPool(parentPool) {
- push();
- }
-
- /// Creates a RAII object and, optionally, initialize its
- /// diagnostics pool by stealing the diagnostics from another
- /// RAII object (which is assumed to be the current top pool).
- ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other)
- : Actions(P.getActions()),
- DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) {
- if (other) {
- DiagnosticPool.steal(other->DiagnosticPool);
- other->abort();
- }
- push();
- }
-
- ~ParsingDeclRAIIObject() {
- abort();
- }
-
- sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() {
- return DiagnosticPool;
- }
- const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
- return DiagnosticPool;
- }
-
- /// Resets the RAII object for a new declaration.
- void reset() {
- abort();
- push();
- }
-
- /// Signals that the context was completed without an appropriate
- /// declaration being parsed.
- void abort() {
- pop(nullptr);
- }
-
- void complete(Decl *D) {
- assert(!Popped && "ParsingDeclaration has already been popped!");
- pop(D);
- }
-
- /// Unregister this object from Sema, but remember all the
- /// diagnostics that were emitted into it.
- void abortAndRemember() {
- pop(nullptr);
- }
-
- private:
- void push() {
- State = Actions.PushParsingDeclaration(DiagnosticPool);
- Popped = false;
- }
-
- void pop(Decl *D) {
- if (!Popped) {
- Actions.PopParsingDeclaration(State, D);
- Popped = true;
- }
- }
- };
-
- /// A class for parsing a DeclSpec.
- class ParsingDeclSpec : public DeclSpec {
- ParsingDeclRAIIObject ParsingRAII;
-
- public:
- ParsingDeclSpec(Parser &P)
- : DeclSpec(P.getAttrFactory()),
- ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {}
- ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII)
- : DeclSpec(P.getAttrFactory()),
- ParsingRAII(P, RAII) {}
-
- const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
- return ParsingRAII.getDelayedDiagnosticPool();
- }
-
- void complete(Decl *D) {
- ParsingRAII.complete(D);
- }
-
- void abort() {
- ParsingRAII.abort();
- }
- };
-
- /// A class for parsing a declarator.
- class ParsingDeclarator : public Declarator {
- ParsingDeclRAIIObject ParsingRAII;
-
- public:
- ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C)
- : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
- }
-
- const ParsingDeclSpec &getDeclSpec() const {
- return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec());
- }
-
- ParsingDeclSpec &getMutableDeclSpec() const {
- return const_cast<ParsingDeclSpec&>(getDeclSpec());
- }
-
- void clear() {
- Declarator::clear();
- ParsingRAII.reset();
- }
-
- void complete(Decl *D) {
- ParsingRAII.complete(D);
- }
- };
-
- /// A class for parsing a field declarator.
- class ParsingFieldDeclarator : public FieldDeclarator {
- ParsingDeclRAIIObject ParsingRAII;
-
- public:
- ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS)
- : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
- }
-
- const ParsingDeclSpec &getDeclSpec() const {
- return static_cast<const ParsingDeclSpec&>(D.getDeclSpec());
- }
-
- ParsingDeclSpec &getMutableDeclSpec() const {
- return const_cast<ParsingDeclSpec&>(getDeclSpec());
- }
-
- void complete(Decl *D) {
- ParsingRAII.complete(D);
- }
- };
-
- /// ExtensionRAIIObject - This saves the state of extension warnings when
- /// constructed and disables them. When destructed, it restores them back to
- /// the way they used to be. This is used to handle __extension__ in the
- /// parser.
- class ExtensionRAIIObject {
- ExtensionRAIIObject(const ExtensionRAIIObject &) = delete;
- void operator=(const ExtensionRAIIObject &) = delete;
-
- DiagnosticsEngine &Diags;
- public:
- ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) {
- Diags.IncrementAllExtensionsSilenced();
- }
-
- ~ExtensionRAIIObject() {
- Diags.DecrementAllExtensionsSilenced();
- }
- };
-
- /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and
- /// restores it when destroyed. This says that "foo:" should not be
- /// considered a possible typo for "foo::" for error recovery purposes.
- class ColonProtectionRAIIObject {
- Parser &P;
- bool OldVal;
- public:
- ColonProtectionRAIIObject(Parser &p, bool Value = true)
- : P(p), OldVal(P.ColonIsSacred) {
- P.ColonIsSacred = Value;
- }
-
- /// restore - This can be used to restore the state early, before the dtor
- /// is run.
- void restore() {
- P.ColonIsSacred = OldVal;
- }
-
- ~ColonProtectionRAIIObject() {
- restore();
- }
- };
-
- /// \brief RAII object that makes '>' behave either as an operator
- /// or as the closing angle bracket for a template argument list.
- class GreaterThanIsOperatorScope {
- bool &GreaterThanIsOperator;
- bool OldGreaterThanIsOperator;
- public:
- GreaterThanIsOperatorScope(bool &GTIO, bool Val)
- : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) {
- GreaterThanIsOperator = Val;
- }
-
- ~GreaterThanIsOperatorScope() {
- GreaterThanIsOperator = OldGreaterThanIsOperator;
- }
- };
-
- class InMessageExpressionRAIIObject {
- bool &InMessageExpression;
- bool OldValue;
-
- public:
- InMessageExpressionRAIIObject(Parser &P, bool Value)
- : InMessageExpression(P.InMessageExpression),
- OldValue(P.InMessageExpression) {
- InMessageExpression = Value;
- }
-
- ~InMessageExpressionRAIIObject() {
- InMessageExpression = OldValue;
- }
- };
-
- /// \brief RAII object that makes sure paren/bracket/brace count is correct
- /// after declaration/statement parsing, even when there's a parsing error.
- class ParenBraceBracketBalancer {
- Parser &P;
- unsigned short ParenCount, BracketCount, BraceCount;
- public:
- ParenBraceBracketBalancer(Parser &p)
- : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount),
- BraceCount(p.BraceCount) { }
-
- ~ParenBraceBracketBalancer() {
- P.ParenCount = ParenCount;
- P.BracketCount = BracketCount;
- P.BraceCount = BraceCount;
- }
- };
-
- class PoisonSEHIdentifiersRAIIObject {
- PoisonIdentifierRAIIObject Ident_AbnormalTermination;
- PoisonIdentifierRAIIObject Ident_GetExceptionCode;
- PoisonIdentifierRAIIObject Ident_GetExceptionInfo;
- PoisonIdentifierRAIIObject Ident__abnormal_termination;
- PoisonIdentifierRAIIObject Ident__exception_code;
- PoisonIdentifierRAIIObject Ident__exception_info;
- PoisonIdentifierRAIIObject Ident___abnormal_termination;
- PoisonIdentifierRAIIObject Ident___exception_code;
- PoisonIdentifierRAIIObject Ident___exception_info;
- public:
- PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue)
- : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue),
- Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue),
- Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue),
- Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue),
- Ident__exception_code(Self.Ident__exception_code, NewValue),
- Ident__exception_info(Self.Ident__exception_info, NewValue),
- Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue),
- Ident___exception_code(Self.Ident___exception_code, NewValue),
- Ident___exception_info(Self.Ident___exception_info, NewValue) {
- }
- };
-
- /// \brief RAII class that helps handle the parsing of an open/close delimiter
- /// pair, such as braces { ... } or parentheses ( ... ).
- class BalancedDelimiterTracker : public GreaterThanIsOperatorScope {
- Parser& P;
- tok::TokenKind Kind, Close, FinalToken;
- SourceLocation (Parser::*Consumer)();
- SourceLocation LOpen, LClose;
-
- unsigned short &getDepth() {
- switch (Kind) {
- case tok::l_brace: return P.BraceCount;
- case tok::l_square: return P.BracketCount;
- case tok::l_paren: return P.ParenCount;
- default: llvm_unreachable("Wrong token kind");
- }
- }
-
- enum { MaxDepth = 256 };
-
- bool diagnoseOverflow();
- bool diagnoseMissingClose();
-
- public:
- BalancedDelimiterTracker(Parser& p, tok::TokenKind k,
- tok::TokenKind FinalToken = tok::semi)
- : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true),
- P(p), Kind(k), FinalToken(FinalToken)
- {
- switch (Kind) {
- default: llvm_unreachable("Unexpected balanced token");
- case tok::l_brace:
- Close = tok::r_brace;
- Consumer = &Parser::ConsumeBrace;
- break;
- case tok::l_paren:
- Close = tok::r_paren;
- Consumer = &Parser::ConsumeParen;
- break;
-
- case tok::l_square:
- Close = tok::r_square;
- Consumer = &Parser::ConsumeBracket;
- break;
- }
- }
-
- SourceLocation getOpenLocation() const { return LOpen; }
- SourceLocation getCloseLocation() const { return LClose; }
- SourceRange getRange() const { return SourceRange(LOpen, LClose); }
-
- bool consumeOpen() {
- if (!P.Tok.is(Kind))
- return true;
-
- if (getDepth() < P.getLangOpts().BracketDepth) {
- LOpen = (P.*Consumer)();
- return false;
- }
-
- return diagnoseOverflow();
- }
-
- bool expectAndConsume(unsigned DiagID = diag::err_expected,
- const char *Msg = "",
- tok::TokenKind SkipToTok = tok::unknown);
- bool consumeClose() {
- if (P.Tok.is(Close)) {
- LClose = (P.*Consumer)();
- return false;
- } else if (P.Tok.is(tok::semi) && P.NextToken().is(Close)) {
- SourceLocation SemiLoc = P.ConsumeToken();
- P.Diag(SemiLoc, diag::err_unexpected_semi)
- << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc));
- LClose = (P.*Consumer)();
- return false;
- }
-
- return diagnoseMissingClose();
- }
- void skipToEnd();
- };
-
-} // end namespace clang
-
-#endif
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,
OpenPOWER on IntegriCloud