aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt48
-rw-r--r--bindings/python/clang/cindex.py1
-rw-r--r--cmake/caches/Apple-stage2-ThinLTO.cmake6
-rw-r--r--cmake/caches/Fuchsia-stage2.cmake66
-rw-r--r--cmake/caches/Fuchsia.cmake50
-rw-r--r--cmake/modules/CMakeLists.txt14
-rw-r--r--cmake/modules/ClangConfig.cmake.in6
-rw-r--r--cmake/modules/FindZ3.cmake28
-rw-r--r--docs/AttributeReference.rst3118
-rw-r--r--docs/ClangCommandLineReference.rst2591
-rw-r--r--docs/ClangFormatStyleOptions.rst812
-rw-r--r--docs/ControlFlowIntegrityDesign.rst92
-rw-r--r--docs/DiagnosticsReference.rst630
-rw-r--r--docs/ExternalClangExamples.rst13
-rw-r--r--docs/LTOVisibility.rst17
-rw-r--r--docs/LanguageExtensions.rst38
-rw-r--r--docs/LibASTMatchersReference.html64
-rw-r--r--docs/Modules.rst11
-rw-r--r--docs/ReleaseNotes.rst251
-rw-r--r--docs/SanitizerCoverage.rst27
-rw-r--r--docs/SourceBasedCodeCoverage.rst3
-rw-r--r--docs/UndefinedBehaviorSanitizer.rst24
-rw-r--r--docs/UsersManual.rst37
-rw-r--r--docs/analyzer/DebugChecks.rst8
-rw-r--r--docs/analyzer/conf.py6
-rw-r--r--docs/conf.py6
-rw-r--r--docs/doxygen.cfg.in6
-rw-r--r--docs/index.rst1
-rw-r--r--docs/tools/dump_format_style.py3
-rw-r--r--examples/clang-interpreter/CMakeLists.txt1
-rw-r--r--include/clang-c/Index.h23
-rw-r--r--include/clang/AST/ASTContext.h223
-rw-r--r--include/clang/AST/ASTVector.h1
-rw-r--r--include/clang/AST/BuiltinTypes.def3
-rw-r--r--include/clang/AST/Decl.h44
-rw-r--r--include/clang/AST/DeclBase.h14
-rw-r--r--include/clang/AST/DeclCXX.h146
-rw-r--r--include/clang/AST/DeclContextInternals.h2
-rw-r--r--include/clang/AST/DeclObjC.h72
-rw-r--r--include/clang/AST/DeclTemplate.h136
-rw-r--r--include/clang/AST/DeclarationName.h43
-rw-r--r--include/clang/AST/Expr.h176
-rw-r--r--include/clang/AST/ExprCXX.h95
-rw-r--r--include/clang/AST/ExternalASTMerger.h51
-rw-r--r--include/clang/AST/ExternalASTSource.h11
-rw-r--r--include/clang/AST/ODRHash.h84
-rw-r--r--include/clang/AST/OpenMPClause.h100
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h31
-rw-r--r--include/clang/AST/Stmt.h25
-rw-r--r--include/clang/AST/StmtCXX.h108
-rw-r--r--include/clang/AST/StmtIterator.h16
-rw-r--r--include/clang/AST/StmtOpenMP.h75
-rw-r--r--include/clang/AST/TemplateBase.h12
-rw-r--r--include/clang/AST/Type.h208
-rw-r--r--include/clang/AST/TypeLoc.h47
-rw-r--r--include/clang/AST/TypeNodes.def4
-rw-r--r--include/clang/AST/TypeOrdering.h2
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h77
-rw-r--r--include/clang/ASTMatchers/Dynamic/VariantValue.h8
-rw-r--r--include/clang/Analysis/CallGraph.h2
-rw-r--r--include/clang/Analysis/CloneDetection.h350
-rw-r--r--include/clang/Basic/AddressSpaces.h24
-rw-r--r--include/clang/Basic/Attr.td68
-rw-r--r--include/clang/Basic/AttrDocs.td193
-rw-r--r--include/clang/Basic/Builtins.def13
-rw-r--r--include/clang/Basic/BuiltinsAMDGPU.def18
-rw-r--r--include/clang/Basic/BuiltinsNVPTX.def24
-rw-r--r--include/clang/Basic/BuiltinsWebAssembly.def6
-rw-r--r--include/clang/Basic/BuiltinsX86.def72
-rw-r--r--include/clang/Basic/DeclNodes.td1
-rw-r--r--include/clang/Basic/Diagnostic.h126
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td12
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td14
-rw-r--r--include/clang/Basic/DiagnosticGroups.td16
-rw-r--r--include/clang/Basic/DiagnosticIDs.h24
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td31
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td247
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td56
-rw-r--r--include/clang/Basic/IdentifierTable.h7
-rw-r--r--include/clang/Basic/LangOptions.def9
-rw-r--r--include/clang/Basic/LangOptions.h52
-rw-r--r--include/clang/Basic/MemoryBufferCache.h80
-rw-r--r--include/clang/Basic/Module.h14
-rw-r--r--include/clang/Basic/ObjCRuntime.h14
-rw-r--r--include/clang/Basic/OpenCLImageTypes.def2
-rw-r--r--include/clang/Basic/OpenMPKinds.h5
-rw-r--r--include/clang/Basic/Sanitizers.def5
-rw-r--r--include/clang/Basic/SourceLocation.h3
-rw-r--r--include/clang/Basic/Specifiers.h5
-rw-r--r--include/clang/Basic/StmtNodes.td3
-rw-r--r--include/clang/Basic/TargetInfo.h24
-rw-r--r--include/clang/Basic/TokenKinds.def3
-rw-r--r--include/clang/Basic/TypeTraits.h1
-rw-r--r--include/clang/Basic/VirtualFileSystem.h2
-rw-r--r--include/clang/Basic/XRayLists.h54
-rw-r--r--include/clang/Basic/arm_neon.td2
-rw-r--r--include/clang/CodeGen/BackendUtil.h5
-rw-r--r--include/clang/CodeGen/CodeGenABITypes.h2
-rw-r--r--include/clang/CodeGen/CodeGenAction.h35
-rw-r--r--include/clang/CodeGen/ConstantInitBuilder.h561
-rw-r--r--include/clang/CodeGen/ConstantInitFuture.h111
-rw-r--r--include/clang/CodeGen/ModuleBuilder.h4
-rw-r--r--include/clang/Config/config.h.cmake3
-rw-r--r--include/clang/Driver/CC1Options.td23
-rw-r--r--include/clang/Driver/CLCompatOptions.td2
-rw-r--r--include/clang/Driver/ClangOptionDocs.td36
-rw-r--r--include/clang/Driver/Driver.h20
-rw-r--r--include/clang/Driver/Job.h10
-rw-r--r--include/clang/Driver/Options.h7
-rw-r--r--include/clang/Driver/Options.td453
-rw-r--r--include/clang/Driver/SanitizerArgs.h2
-rw-r--r--include/clang/Driver/Tool.h2
-rw-r--r--include/clang/Driver/ToolChain.h15
-rw-r--r--include/clang/Driver/XRayArgs.h38
-rw-r--r--include/clang/Format/Format.h750
-rw-r--r--include/clang/Frontend/ASTConsumers.h2
-rw-r--r--include/clang/Frontend/ASTUnit.h4
-rw-r--r--include/clang/Frontend/CodeGenOptions.def14
-rw-r--r--include/clang/Frontend/CodeGenOptions.h30
-rw-r--r--include/clang/Frontend/CompilerInstance.h16
-rw-r--r--include/clang/Frontend/FrontendActions.h2
-rw-r--r--include/clang/Frontend/FrontendOptions.h11
-rw-r--r--include/clang/Frontend/LangStandard.h6
-rw-r--r--include/clang/Frontend/LangStandards.def8
-rw-r--r--include/clang/Frontend/PCHContainerOperations.h3
-rw-r--r--include/clang/Index/IndexSymbol.h9
-rw-r--r--include/clang/Index/IndexingAction.h10
-rw-r--r--include/clang/Index/USRGeneration.h3
-rw-r--r--include/clang/Lex/HeaderSearchOptions.h6
-rw-r--r--include/clang/Lex/Preprocessor.h22
-rw-r--r--include/clang/Parse/Parser.h83
-rw-r--r--include/clang/Parse/RAIIObjectsForParser.h (renamed from lib/Parse/RAIIObjectsForParser.h)20
-rw-r--r--include/clang/Sema/AttributeList.h1
-rw-r--r--include/clang/Sema/DeclSpec.h63
-rw-r--r--include/clang/Sema/IdentifierResolver.h16
-rw-r--r--include/clang/Sema/Initialization.h40
-rw-r--r--include/clang/Sema/Lookup.h2
-rw-r--r--include/clang/Sema/MultiplexExternalSemaSource.h2
-rw-r--r--include/clang/Sema/Overload.h1
-rw-r--r--include/clang/Sema/Ownership.h1
-rw-r--r--include/clang/Sema/ScopeInfo.h81
-rw-r--r--include/clang/Sema/Sema.h369
-rw-r--r--include/clang/Sema/Template.h34
-rw-r--r--include/clang/Serialization/ASTBitCodes.h53
-rw-r--r--include/clang/Serialization/ASTDeserializationListener.h4
-rw-r--r--include/clang/Serialization/ASTReader.h98
-rw-r--r--include/clang/Serialization/ASTWriter.h36
-rw-r--r--include/clang/Serialization/Module.h114
-rw-r--r--include/clang/Serialization/ModuleManager.h34
-rw-r--r--include/clang/StaticAnalyzer/Checkers/Checkers.td10
-rw-r--r--include/clang/StaticAnalyzer/Core/Analyses.def1
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h16
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h21
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h283
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h59
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h92
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h31
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h64
-rw-r--r--include/clang/Tooling/Refactoring/AtomicChange.h135
-rw-r--r--lib/AST/ASTContext.cpp207
-rw-r--r--lib/AST/ASTDumper.cpp48
-rw-r--r--lib/AST/ASTImporter.cpp363
-rw-r--r--lib/AST/CMakeLists.txt2
-rw-r--r--lib/AST/CXXInheritance.cpp4
-rw-r--r--lib/AST/Decl.cpp54
-rw-r--r--lib/AST/DeclBase.cpp1
-rw-r--r--lib/AST/DeclCXX.cpp84
-rw-r--r--lib/AST/DeclObjC.cpp4
-rw-r--r--lib/AST/DeclPrinter.cpp25
-rw-r--r--lib/AST/DeclTemplate.cpp37
-rw-r--r--lib/AST/DeclarationName.cpp105
-rw-r--r--lib/AST/Expr.cpp29
-rw-r--r--lib/AST/ExprCXX.cpp10
-rw-r--r--lib/AST/ExprClassification.cpp4
-rw-r--r--lib/AST/ExprConstant.cpp337
-rw-r--r--lib/AST/ExternalASTMerger.cpp185
-rw-r--r--lib/AST/ExternalASTSource.cpp5
-rw-r--r--lib/AST/ItaniumMangle.cpp38
-rw-r--r--lib/AST/Mangle.cpp8
-rw-r--r--lib/AST/MicrosoftMangle.cpp57
-rw-r--r--lib/AST/NSAPI.cpp1
-rw-r--r--lib/AST/ODRHash.cpp361
-rw-r--r--lib/AST/OpenMPClause.cpp12
-rw-r--r--lib/AST/Stmt.cpp2
-rw-r--r--lib/AST/StmtCXX.cpp27
-rw-r--r--lib/AST/StmtOpenMP.cpp40
-rw-r--r--lib/AST/StmtPrinter.cpp7
-rw-r--r--lib/AST/StmtProfile.cpp237
-rw-r--r--lib/AST/TemplateBase.cpp4
-rw-r--r--lib/AST/Type.cpp140
-rw-r--r--lib/AST/TypeLoc.cpp1
-rw-r--r--lib/AST/TypePrinter.cpp40
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp7
-rw-r--r--lib/Analysis/BodyFarm.cpp4
-rw-r--r--lib/Analysis/CFG.cpp2
-rw-r--r--lib/Analysis/CallGraph.cpp1
-rw-r--r--lib/Analysis/CloneDetection.cpp887
-rw-r--r--lib/Analysis/OSLog.cpp3
-rw-r--r--lib/Analysis/ReachableCode.cpp19
-rw-r--r--lib/Analysis/ThreadSafetyTIL.cpp4
-rw-r--r--lib/Basic/CMakeLists.txt2
-rw-r--r--lib/Basic/Diagnostic.cpp171
-rw-r--r--lib/Basic/DiagnosticIDs.cpp5
-rw-r--r--lib/Basic/FileManager.cpp7
-rw-r--r--lib/Basic/IdentifierTable.cpp21
-rw-r--r--lib/Basic/LangOptions.cpp2
-rw-r--r--lib/Basic/MemoryBufferCache.cpp48
-rw-r--r--lib/Basic/Module.cpp2
-rw-r--r--lib/Basic/OpenMPKinds.cpp73
-rw-r--r--lib/Basic/SourceManager.cpp13
-rw-r--r--lib/Basic/TargetInfo.cpp5
-rw-r--r--lib/Basic/Targets.cpp861
-rw-r--r--lib/Basic/Version.cpp2
-rw-r--r--lib/Basic/VirtualFileSystem.cpp24
-rw-r--r--lib/Basic/XRayLists.cpp53
-rw-r--r--lib/CodeGen/ABIInfo.h1
-rw-r--r--lib/CodeGen/BackendUtil.cpp416
-rw-r--r--lib/CodeGen/CGAtomic.cpp2
-rw-r--r--lib/CodeGen/CGBlocks.cpp419
-rw-r--r--lib/CodeGen/CGBuiltin.cpp261
-rw-r--r--lib/CodeGen/CGCUDANV.cpp2
-rw-r--r--lib/CodeGen/CGCXX.cpp2
-rw-r--r--lib/CodeGen/CGCXXABI.h27
-rw-r--r--lib/CodeGen/CGCall.cpp588
-rw-r--r--lib/CodeGen/CGCall.h52
-rw-r--r--lib/CodeGen/CGClass.cpp66
-rw-r--r--lib/CodeGen/CGCleanup.cpp43
-rw-r--r--lib/CodeGen/CGCoroutine.cpp277
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp252
-rw-r--r--lib/CodeGen/CGDebugInfo.h67
-rw-r--r--lib/CodeGen/CGDecl.cpp81
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp2
-rw-r--r--lib/CodeGen/CGException.cpp17
-rw-r--r--lib/CodeGen/CGExpr.cpp273
-rw-r--r--lib/CodeGen/CGExprAgg.cpp9
-rw-r--r--lib/CodeGen/CGExprCXX.cpp50
-rw-r--r--lib/CodeGen/CGExprComplex.cpp16
-rw-r--r--lib/CodeGen/CGExprScalar.cpp217
-rw-r--r--lib/CodeGen/CGGPUBuiltin.cpp (renamed from lib/CodeGen/CGCUDABuiltin.cpp)13
-rw-r--r--lib/CodeGen/CGObjC.cpp119
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp4
-rw-r--r--lib/CodeGen/CGObjCMac.cpp26
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.cpp3
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.cpp306
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.h53
-rw-r--r--lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp1710
-rw-r--r--lib/CodeGen/CGOpenMPRuntimeNVPTX.h128
-rw-r--r--lib/CodeGen/CGStmt.cpp10
-rw-r--r--lib/CodeGen/CGStmtOpenMP.cpp298
-rw-r--r--lib/CodeGen/CGVTables.cpp20
-rw-r--r--lib/CodeGen/CMakeLists.txt4
-rw-r--r--lib/CodeGen/CodeGenAction.cpp293
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp81
-rw-r--r--lib/CodeGen/CodeGenFunction.h173
-rw-r--r--lib/CodeGen/CodeGenModule.cpp199
-rw-r--r--lib/CodeGen/CodeGenModule.h63
-rw-r--r--lib/CodeGen/CodeGenPGO.cpp34
-rw-r--r--lib/CodeGen/CodeGenPGO.h3
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp4
-rw-r--r--lib/CodeGen/CodeGenTypes.h7
-rw-r--r--lib/CodeGen/ConstantBuilder.h444
-rw-r--r--lib/CodeGen/ConstantInitBuilder.cpp280
-rw-r--r--lib/CodeGen/CoverageMappingGen.cpp10
-rw-r--r--lib/CodeGen/EHScopeStack.h2
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp86
-rw-r--r--lib/CodeGen/MacroPPCallbacks.cpp207
-rw-r--r--lib/CodeGen/MacroPPCallbacks.h117
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp82
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp8
-rw-r--r--lib/CodeGen/ObjectFilePCHContainerOperations.cpp9
-rw-r--r--lib/CodeGen/TargetInfo.cpp121
-rw-r--r--lib/Driver/CMakeLists.txt43
-rw-r--r--lib/Driver/CrossWindowsToolChain.cpp125
-rw-r--r--lib/Driver/Driver.cpp185
-rw-r--r--lib/Driver/DriverOptions.cpp4
-rw-r--r--lib/Driver/Job.cpp26
-rw-r--r--lib/Driver/MSVCToolChain.cpp892
-rw-r--r--lib/Driver/MinGWToolChain.cpp257
-rw-r--r--lib/Driver/Multilib.cpp2
-rw-r--r--lib/Driver/SanitizerArgs.cpp13
-rw-r--r--lib/Driver/ToolChain.cpp27
-rw-r--r--lib/Driver/ToolChains.cpp5342
-rw-r--r--lib/Driver/ToolChains.h1388
-rw-r--r--lib/Driver/ToolChains/AMDGPU.cpp45
-rw-r--r--lib/Driver/ToolChains/AMDGPU.h54
-rw-r--r--lib/Driver/ToolChains/AVR.cpp44
-rw-r--r--lib/Driver/ToolChains/AVR.h49
-rw-r--r--lib/Driver/ToolChains/Arch/AArch64.cpp199
-rw-r--r--lib/Driver/ToolChains/Arch/AArch64.h35
-rw-r--r--lib/Driver/ToolChains/Arch/ARM.cpp547
-rw-r--r--lib/Driver/ToolChains/Arch/ARM.h60
-rw-r--r--lib/Driver/ToolChains/Arch/Mips.cpp403
-rw-r--r--lib/Driver/ToolChains/Arch/Mips.h62
-rw-r--r--lib/Driver/ToolChains/Arch/PPC.cpp131
-rw-r--r--lib/Driver/ToolChains/Arch/PPC.h45
-rw-r--r--lib/Driver/ToolChains/Arch/Sparc.cpp100
-rw-r--r--lib/Driver/ToolChains/Arch/Sparc.h42
-rw-r--r--lib/Driver/ToolChains/Arch/SystemZ.cpp41
-rw-r--r--lib/Driver/ToolChains/Arch/SystemZ.h32
-rw-r--r--lib/Driver/ToolChains/Arch/X86.cpp173
-rw-r--r--lib/Driver/ToolChains/Arch/X86.h37
-rw-r--r--lib/Driver/ToolChains/Bitrig.cpp190
-rw-r--r--lib/Driver/ToolChains/Bitrig.h79
-rw-r--r--lib/Driver/ToolChains/Clang.cpp5160
-rw-r--r--lib/Driver/ToolChains/Clang.h149
-rw-r--r--lib/Driver/ToolChains/CloudABI.cpp145
-rw-r--r--lib/Driver/ToolChains/CloudABI.h69
-rw-r--r--lib/Driver/ToolChains/CommonArgs.cpp973
-rw-r--r--lib/Driver/ToolChains/CommonArgs.h96
-rw-r--r--lib/Driver/ToolChains/Contiki.cpp28
-rw-r--r--lib/Driver/ToolChains/Contiki.h38
-rw-r--r--lib/Driver/ToolChains/CrossWindows.cpp309
-rw-r--r--lib/Driver/ToolChains/CrossWindows.h88
-rw-r--r--lib/Driver/ToolChains/Cuda.cpp488
-rw-r--r--lib/Driver/ToolChains/Cuda.h177
-rw-r--r--lib/Driver/ToolChains/Darwin.cpp1910
-rw-r--r--lib/Driver/ToolChains/Darwin.h488
-rw-r--r--lib/Driver/ToolChains/DragonFly.cpp197
-rw-r--r--lib/Driver/ToolChains/DragonFly.h68
-rw-r--r--lib/Driver/ToolChains/FreeBSD.cpp395
-rw-r--r--lib/Driver/ToolChains/FreeBSD.h86
-rw-r--r--lib/Driver/ToolChains/Fuchsia.cpp229
-rw-r--r--lib/Driver/ToolChains/Fuchsia.h79
-rw-r--r--lib/Driver/ToolChains/Gnu.cpp2426
-rw-r--r--lib/Driver/ToolChains/Gnu.h351
-rw-r--r--lib/Driver/ToolChains/Haiku.cpp33
-rw-r--r--lib/Driver/ToolChains/Haiku.h40
-rw-r--r--lib/Driver/ToolChains/Hexagon.cpp457
-rw-r--r--lib/Driver/ToolChains/Hexagon.h99
-rw-r--r--lib/Driver/ToolChains/Lanai.h39
-rw-r--r--lib/Driver/ToolChains/Linux.cpp901
-rw-r--r--lib/Driver/ToolChains/Linux.h57
-rw-r--r--lib/Driver/ToolChains/MSVC.cpp1421
-rw-r--r--lib/Driver/ToolChains/MSVC.h141
-rw-r--r--lib/Driver/ToolChains/MSVCSetupApi.h514
-rw-r--r--lib/Driver/ToolChains/MinGW.cpp471
-rw-r--r--lib/Driver/ToolChains/MinGW.h102
-rw-r--r--lib/Driver/ToolChains/Minix.cpp109
-rw-r--r--lib/Driver/ToolChains/Minix.h66
-rw-r--r--lib/Driver/ToolChains/MipsLinux.cpp128
-rw-r--r--lib/Driver/ToolChains/MipsLinux.h62
-rw-r--r--lib/Driver/ToolChains/Myriad.cpp286
-rw-r--r--lib/Driver/ToolChains/Myriad.h102
-rw-r--r--lib/Driver/ToolChains/NaCl.cpp363
-rw-r--r--lib/Driver/ToolChains/NaCl.h87
-rw-r--r--lib/Driver/ToolChains/NetBSD.cpp412
-rw-r--r--lib/Driver/ToolChains/NetBSD.h79
-rw-r--r--lib/Driver/ToolChains/OpenBSD.cpp234
-rw-r--r--lib/Driver/ToolChains/OpenBSD.h76
-rw-r--r--lib/Driver/ToolChains/PS4CPU.cpp419
-rw-r--r--lib/Driver/ToolChains/PS4CPU.h93
-rw-r--r--lib/Driver/ToolChains/Solaris.cpp193
-rw-r--r--lib/Driver/ToolChains/Solaris.h75
-rw-r--r--lib/Driver/ToolChains/TCE.cpp47
-rw-r--r--lib/Driver/ToolChains/TCE.h47
-rw-r--r--lib/Driver/ToolChains/WebAssembly.cpp163
-rw-r--r--lib/Driver/ToolChains/WebAssembly.h77
-rw-r--r--lib/Driver/ToolChains/XCore.cpp149
-rw-r--r--lib/Driver/ToolChains/XCore.h82
-rw-r--r--lib/Driver/Tools.cpp12226
-rw-r--r--lib/Driver/Tools.h1010
-rw-r--r--lib/Driver/XRayArgs.cpp114
-rw-r--r--lib/Format/BreakableToken.cpp736
-rw-r--r--lib/Format/BreakableToken.h362
-rw-r--r--lib/Format/CMakeLists.txt2
-rw-r--r--lib/Format/Comments.cpp36
-rw-r--r--lib/Format/Comments.h33
-rw-r--r--lib/Format/ContinuationIndenter.cpp262
-rw-r--r--lib/Format/ContinuationIndenter.h19
-rw-r--r--lib/Format/Format.cpp147
-rw-r--r--lib/Format/FormatToken.h22
-rw-r--r--lib/Format/FormatTokenLexer.cpp38
-rw-r--r--lib/Format/FormatTokenLexer.h1
-rw-r--r--lib/Format/NamespaceEndCommentsFixer.cpp175
-rw-r--r--lib/Format/NamespaceEndCommentsFixer.h37
-rw-r--r--lib/Format/TokenAnnotator.cpp223
-rw-r--r--lib/Format/TokenAnnotator.h4
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp46
-rw-r--r--lib/Format/UnwrappedLineFormatter.h8
-rw-r--r--lib/Format/UnwrappedLineParser.cpp286
-rw-r--r--lib/Format/UnwrappedLineParser.h35
-rw-r--r--lib/Format/WhitespaceManager.cpp274
-rw-r--r--lib/Format/WhitespaceManager.h44
-rw-r--r--lib/Frontend/ASTConsumers.cpp39
-rw-r--r--lib/Frontend/ASTUnit.cpp32
-rw-r--r--lib/Frontend/CompilerInstance.cpp57
-rw-r--r--lib/Frontend/CompilerInvocation.cpp289
-rw-r--r--lib/Frontend/FrontendAction.cpp89
-rw-r--r--lib/Frontend/FrontendActions.cpp10
-rw-r--r--lib/Frontend/InitPreprocessor.cpp17
-rw-r--r--lib/Frontend/Rewrite/RewriteMacros.cpp2
-rw-r--r--lib/Frontend/Rewrite/RewriteModernObjC.cpp6
-rw-r--r--lib/Frontend/Rewrite/RewriteObjC.cpp6
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp2
-rw-r--r--lib/Headers/CMakeLists.txt1
-rw-r--r--lib/Headers/altivec.h44
-rw-r--r--lib/Headers/avx2intrin.h2
-rw-r--r--lib/Headers/avx512bwintrin.h104
-rw-r--r--lib/Headers/avx512dqintrin.h95
-rw-r--r--lib/Headers/avx512fintrin.h189
-rw-r--r--lib/Headers/avx512vldqintrin.h42
-rw-r--r--lib/Headers/avx512vlintrin.h45
-rw-r--r--lib/Headers/avxintrin.h296
-rw-r--r--lib/Headers/clzerointrin.h50
-rw-r--r--lib/Headers/emmintrin.h38
-rw-r--r--lib/Headers/f16cintrin.h10
-rw-r--r--lib/Headers/htmxlintrin.h14
-rw-r--r--lib/Headers/intrin.h50
-rw-r--r--lib/Headers/mmintrin.h2
-rw-r--r--lib/Headers/module.modulemap1
-rw-r--r--lib/Headers/opencl-c.h884
-rw-r--r--lib/Headers/pmmintrin.h12
-rw-r--r--lib/Headers/prfchwintrin.h24
-rw-r--r--lib/Headers/smmintrin.h2013
-rw-r--r--lib/Headers/stdarg.h3
-rw-r--r--lib/Headers/tgmath.h16
-rw-r--r--lib/Headers/x86intrin.h4
-rw-r--r--lib/Headers/xmmintrin.h14
-rw-r--r--lib/Headers/xopintrin.h4
-rw-r--r--lib/Index/CMakeLists.txt1
-rw-r--r--lib/Index/CommentToXML.cpp6
-rw-r--r--lib/Index/IndexBody.cpp16
-rw-r--r--lib/Index/IndexDecl.cpp155
-rw-r--r--lib/Index/IndexSymbol.cpp70
-rw-r--r--lib/Index/IndexTypeSourceInfo.cpp32
-rw-r--r--lib/Index/IndexingAction.cpp17
-rw-r--r--lib/Index/IndexingContext.cpp93
-rw-r--r--lib/Index/IndexingContext.h3
-rw-r--r--lib/Index/USRGeneration.cpp20
-rw-r--r--lib/Lex/HeaderSearch.cpp6
-rw-r--r--lib/Lex/Lexer.cpp20
-rw-r--r--lib/Lex/ModuleMap.cpp31
-rw-r--r--lib/Lex/PPCaching.cpp30
-rw-r--r--lib/Lex/PPDirectives.cpp11
-rw-r--r--lib/Lex/PPMacroExpansion.cpp1
-rw-r--r--lib/Lex/Pragma.cpp11
-rw-r--r--lib/Lex/Preprocessor.cpp10
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp8
-rw-r--r--lib/Parse/ParseDecl.cpp348
-rw-r--r--lib/Parse/ParseDeclCXX.cpp193
-rw-r--r--lib/Parse/ParseExpr.cpp83
-rw-r--r--lib/Parse/ParseExprCXX.cpp91
-rw-r--r--lib/Parse/ParseInit.cpp2
-rw-r--r--lib/Parse/ParseObjc.cpp101
-rw-r--r--lib/Parse/ParseOpenMP.cpp11
-rw-r--r--lib/Parse/ParsePragma.cpp153
-rw-r--r--lib/Parse/ParseStmt.cpp25
-rw-r--r--lib/Parse/ParseStmtAsm.cpp19
-rw-r--r--lib/Parse/ParseTemplate.cpp33
-rw-r--r--lib/Parse/Parser.cpp52
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp17
-rw-r--r--lib/Sema/CoroutineStmtBuilder.h70
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp9
-rw-r--r--lib/Sema/ScopeInfo.cpp19
-rw-r--r--lib/Sema/Sema.cpp33
-rw-r--r--lib/Sema/SemaAttr.cpp17
-rw-r--r--lib/Sema/SemaCUDA.cpp14
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp35
-rw-r--r--lib/Sema/SemaCast.cpp40
-rw-r--r--lib/Sema/SemaChecking.cpp210
-rw-r--r--lib/Sema/SemaCodeComplete.cpp163
-rw-r--r--lib/Sema/SemaCoroutine.cpp843
-rw-r--r--lib/Sema/SemaDecl.cpp680
-rw-r--r--lib/Sema/SemaDeclAttr.cpp308
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1057
-rw-r--r--lib/Sema/SemaDeclObjC.cpp16
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--lib/Sema/SemaExpr.cpp450
-rw-r--r--lib/Sema/SemaExprCXX.cpp345
-rw-r--r--lib/Sema/SemaExprMember.cpp47
-rw-r--r--lib/Sema/SemaExprObjC.cpp136
-rw-r--r--lib/Sema/SemaInit.cpp357
-rw-r--r--lib/Sema/SemaLambda.cpp73
-rw-r--r--lib/Sema/SemaLookup.cpp87
-rw-r--r--lib/Sema/SemaObjCProperty.cpp37
-rw-r--r--lib/Sema/SemaOpenMP.cpp562
-rw-r--r--lib/Sema/SemaOverload.cpp177
-rw-r--r--lib/Sema/SemaPseudoObject.cpp33
-rw-r--r--lib/Sema/SemaStmt.cpp48
-rw-r--r--lib/Sema/SemaStmtAsm.cpp5
-rw-r--r--lib/Sema/SemaStmtAttr.cpp27
-rw-r--r--lib/Sema/SemaTemplate.cpp807
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp384
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp262
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp208
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp1
-rw-r--r--lib/Sema/SemaType.cpp248
-rw-r--r--lib/Sema/TreeTransform.h552
-rw-r--r--lib/Serialization/ASTCommon.cpp4
-rw-r--r--lib/Serialization/ASTReader.cpp1362
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp197
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp20
-rw-r--r--lib/Serialization/ASTWriter.cpp386
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp20
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp16
-rw-r--r--lib/Serialization/GeneratePCH.cpp7
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp76
-rw-r--r--lib/Serialization/Module.cpp22
-rw-r--r--lib/Serialization/ModuleManager.cpp255
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp49
-rw-r--r--lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp70
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt1
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp32
-rw-r--r--lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp76
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/CloneChecker.cpp100
-rw-r--r--lib/StaticAnalyzer/Checkers/ConversionChecker.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp85
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp172
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp49
-rw-r--r--lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp481
-rw-r--r--lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp26
-rw-r--r--lib/StaticAnalyzer/Checkers/ValistChecker.cpp85
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp8
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt17
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp81
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/ConstraintManager.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/DynamicTypeMap.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp156
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp9
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp9
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp62
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp102
-rw-r--r--lib/StaticAnalyzer/Core/RangedConstraintManager.cpp204
-rw-r--r--lib/StaticAnalyzer/Core/RangedConstraintManager.h (renamed from lib/StaticAnalyzer/Core/SimpleConstraintManager.h)69
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp10
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp230
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp102
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp35
-rw-r--r--lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp1618
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp4
-rw-r--r--lib/Tooling/CMakeLists.txt1
-rw-r--r--lib/Tooling/Refactoring.cpp15
-rw-r--r--lib/Tooling/Refactoring/AtomicChange.cpp178
-rw-r--r--lib/Tooling/Refactoring/CMakeLists.txt12
-rw-r--r--lib/Tooling/Tooling.cpp2
-rw-r--r--test/ARCMT/lit.local.cfg2
-rw-r--r--test/ASTMerge/asm/Inputs/asm-function.cpp10
-rw-r--r--test/ASTMerge/asm/test.cpp1
-rw-r--r--test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec1.cpp118
-rw-r--r--test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec2.cpp79
-rw-r--r--test/ASTMerge/class-template-partial-spec/test.cpp25
-rw-r--r--test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp4
-rw-r--r--test/ASTMerge/exprs-cpp/test.cpp2
-rw-r--r--test/ASTMerge/struct/Inputs/struct1.c16
-rw-r--r--test/ASTMerge/struct/Inputs/struct2.c16
-rw-r--r--test/ASTMerge/struct/test.c7
-rw-r--r--test/Analysis/CFContainers-invalid.c2
-rw-r--r--test/Analysis/CFContainers.mm2
-rw-r--r--test/Analysis/CFDateGC.m2
-rw-r--r--test/Analysis/CFNumber.c2
-rw-r--r--test/Analysis/CFRetainRelease_NSAssertionHandler.m2
-rw-r--r--test/Analysis/CGColorSpace.c2
-rw-r--r--test/Analysis/CheckNSError.m2
-rw-r--r--test/Analysis/DeallocMissingRelease.m6
-rw-r--r--test/Analysis/DeallocUseAfterFreeErrors.m2
-rw-r--r--test/Analysis/DynamicTypePropagation.m2
-rw-r--r--test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp4
-rw-r--r--test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp2
-rw-r--r--test/Analysis/Malloc+NewDelete_intersections.cpp4
-rw-r--r--test/Analysis/MemRegion.cpp2
-rw-r--r--test/Analysis/MismatchedDeallocator-checker-test.mm2
-rw-r--r--test/Analysis/MismatchedDeallocator-path-notes.cpp4
-rw-r--r--test/Analysis/MissingDealloc.m4
-rw-r--r--test/Analysis/MisusedMovedObject.cpp619
-rw-r--r--test/Analysis/NSContainers.m2
-rw-r--r--test/Analysis/NSPanel.m2
-rw-r--r--test/Analysis/NSString.m8
-rw-r--r--test/Analysis/NSWindow.m2
-rw-r--r--test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp4
-rw-r--r--test/Analysis/NewDelete-checker-test.cpp6
-rw-r--r--test/Analysis/NewDelete-custom.cpp4
-rw-r--r--test/Analysis/NewDelete-intersections.mm4
-rw-r--r--test/Analysis/NewDelete-path-notes.cpp4
-rw-r--r--test/Analysis/NewDelete-variadic.cpp2
-rw-r--r--test/Analysis/NewDeleteLeaks-PR18394.cpp2
-rw-r--r--test/Analysis/NewDeleteLeaks-PR19102.cpp2
-rw-r--r--test/Analysis/NoReturn.m2
-rw-r--r--test/Analysis/OSAtomic_mac.cpp2
-rw-r--r--test/Analysis/ObjCProperties.m2
-rw-r--r--test/Analysis/ObjCPropertiesSyntaxChecks.m9
-rw-r--r--test/Analysis/ObjCRetSigs.m2
-rw-r--r--test/Analysis/PR12905.c2
-rw-r--r--test/Analysis/PR24184.cpp4
-rw-r--r--test/Analysis/PR2599.m2
-rw-r--r--test/Analysis/PR2978.m2
-rw-r--r--test/Analysis/PR3991.m2
-rw-r--r--test/Analysis/PR7218.c2
-rw-r--r--test/Analysis/additive-folding-range-constraints.c2
-rw-r--r--test/Analysis/additive-folding.cpp11
-rw-r--r--test/Analysis/analyzeOneFunction.m2
-rw-r--r--test/Analysis/analyzer-checker-config.c14
-rw-r--r--test/Analysis/analyzer-config.c2
-rw-r--r--test/Analysis/analyzer-config.cpp2
-rw-r--r--test/Analysis/analyzer-display-progress.cpp2
-rw-r--r--test/Analysis/analyzer-display-progress.m2
-rw-r--r--test/Analysis/analyzer-enabled-checkers.c2
-rw-r--r--test/Analysis/analyzer-stats.c2
-rw-r--r--test/Analysis/analyzer_test.py28
-rw-r--r--test/Analysis/array-struct-region.c2
-rw-r--r--test/Analysis/array-struct-region.cpp8
-rw-r--r--test/Analysis/array-struct.c2
-rw-r--r--test/Analysis/atomics.c2
-rw-r--r--test/Analysis/auto-obj-dtors-cfg-output.cpp2
-rw-r--r--test/Analysis/base-init.cpp2
-rw-r--r--test/Analysis/bitwise-ops.c2
-rw-r--r--test/Analysis/block-in-critical-section.cpp78
-rw-r--r--test/Analysis/blocks-no-inline.c4
-rw-r--r--test/Analysis/blocks.m4
-rw-r--r--test/Analysis/blocks.mm4
-rw-r--r--test/Analysis/bool-assignment.c9
-rw-r--r--test/Analysis/bstring.c8
-rw-r--r--test/Analysis/bstring.cpp2
-rw-r--r--test/Analysis/bug_hash_test.cpp2
-rw-r--r--test/Analysis/bug_hash_test.m2
-rw-r--r--test/Analysis/builtin-functions.cpp2
-rw-r--r--test/Analysis/call-invalidation.cpp2
-rw-r--r--test/Analysis/cast-to-struct.cpp16
-rw-r--r--test/Analysis/castexpr-callback.c2
-rw-r--r--test/Analysis/casts.c9
-rw-r--r--test/Analysis/casts.cpp2
-rw-r--r--test/Analysis/casts.m2
-rw-r--r--test/Analysis/cfg.cpp2
-rw-r--r--test/Analysis/cfref_PR2519.c2
-rw-r--r--test/Analysis/cfref_rdar6080742.c2
-rw-r--r--test/Analysis/check-deserialization.cpp4
-rw-r--r--test/Analysis/checker-plugins.c2
-rw-r--r--test/Analysis/chroot.c2
-rw-r--r--test/Analysis/comparison-implicit-casts.cpp4
-rw-r--r--test/Analysis/complex-init-list.cpp2
-rw-r--r--test/Analysis/complex.c2
-rw-r--r--test/Analysis/concrete-address.c2
-rw-r--r--test/Analysis/conditional-operator.cpp2
-rw-r--r--test/Analysis/conditional-path-notes.c4
-rw-r--r--test/Analysis/const-method-call.cpp2
-rw-r--r--test/Analysis/constant-folding.c2
-rw-r--r--test/Analysis/conversion.c70
-rw-r--r--test/Analysis/copypaste/asm.cpp2
-rw-r--r--test/Analysis/copypaste/attributes.cpp2
-rw-r--r--test/Analysis/copypaste/blocks.cpp2
-rw-r--r--test/Analysis/copypaste/call.cpp2
-rw-r--r--test/Analysis/copypaste/catch.cpp2
-rw-r--r--test/Analysis/copypaste/delete.cpp2
-rw-r--r--test/Analysis/copypaste/dependent-exist.cpp2
-rw-r--r--test/Analysis/copypaste/expr-types.cpp2
-rw-r--r--test/Analysis/copypaste/fold.cpp2
-rw-r--r--test/Analysis/copypaste/function-try-block.cpp2
-rw-r--r--test/Analysis/copypaste/functions.cpp2
-rw-r--r--test/Analysis/copypaste/generic.c2
-rw-r--r--test/Analysis/copypaste/labels.cpp2
-rw-r--r--test/Analysis/copypaste/lambda.cpp2
-rw-r--r--test/Analysis/copypaste/macro-complexity.cpp2
-rw-r--r--test/Analysis/copypaste/macros.cpp2
-rw-r--r--test/Analysis/copypaste/objc-methods.m2
-rw-r--r--test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp2
-rw-r--r--test/Analysis/copypaste/plist-diagnostics.cpp2
-rw-r--r--test/Analysis/copypaste/sub-sequences.cpp2
-rw-r--r--test/Analysis/copypaste/suspicious-clones.cpp2
-rw-r--r--test/Analysis/copypaste/text-diagnostics.cpp2
-rw-r--r--test/Analysis/coverage.c2
-rw-r--r--test/Analysis/crash-trace.c2
-rw-r--r--test/Analysis/cstring-syntax-cxx.cpp2
-rw-r--r--test/Analysis/cstring-syntax.c4
-rw-r--r--test/Analysis/ctor.mm2
-rw-r--r--test/Analysis/cxx-crashes.cpp2
-rw-r--r--test/Analysis/cxx-for-range.cpp2
-rw-r--r--test/Analysis/cxx-method-names.cpp2
-rw-r--r--test/Analysis/cxx11-crashes.cpp2
-rw-r--r--test/Analysis/dead-stores.c4
-rw-r--r--test/Analysis/dead-stores.cpp4
-rw-r--r--test/Analysis/dead-stores.m2
-rw-r--r--test/Analysis/debug-CallGraph.c29
-rw-r--r--test/Analysis/default-analyze.m2
-rw-r--r--test/Analysis/default-diagnostic-visitors.c2
-rw-r--r--test/Analysis/delayed-template-parsing-crash.cpp2
-rw-r--r--test/Analysis/delegates.m2
-rw-r--r--test/Analysis/derived-to-base.cpp4
-rw-r--r--test/Analysis/designated-initializer.c2
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.c4
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.cpp2
-rw-r--r--test/Analysis/diagnostics/diag-cross-file-boundaries.c4
-rw-r--r--test/Analysis/diagnostics/explicit-suppression.cpp5
-rw-r--r--test/Analysis/diagnostics/false-positive-suppression.c2
-rw-r--r--test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp4
-rw-r--r--test/Analysis/diagnostics/macros.cpp2
-rw-r--r--test/Analysis/diagnostics/macros.m2
-rw-r--r--test/Analysis/diagnostics/no-prune-paths.c4
-rw-r--r--test/Analysis/diagnostics/plist-diagnostics-include-check.cpp2
-rw-r--r--test/Analysis/diagnostics/report-issues-within-main-file.cpp2
-rw-r--r--test/Analysis/diagnostics/shortest-path-suppression.c2
-rw-r--r--test/Analysis/diagnostics/text-diagnostics.c2
-rw-r--r--test/Analysis/diagnostics/undef-value-caller.c2
-rw-r--r--test/Analysis/diagnostics/undef-value-param.c4
-rw-r--r--test/Analysis/diagnostics/undef-value-param.m14
-rw-r--r--test/Analysis/disable-all-checks.c10
-rw-r--r--test/Analysis/dispatch-once.m4
-rw-r--r--test/Analysis/div-zero.cpp2
-rw-r--r--test/Analysis/division-by-zero.c2
-rw-r--r--test/Analysis/domtest.c2
-rw-r--r--test/Analysis/dtor-cxx11.cpp2
-rw-r--r--test/Analysis/dtor.cpp2
-rw-r--r--test/Analysis/dtors-in-dtor-cfg-output.cpp2
-rw-r--r--test/Analysis/dynamic-cast.cpp2
-rw-r--r--test/Analysis/dynamic_type_check.m2
-rw-r--r--test/Analysis/edges-new.mm4
-rw-r--r--test/Analysis/elementtype.c2
-rw-r--r--test/Analysis/engine/replay-without-inlining.c2
-rw-r--r--test/Analysis/enum.cpp2
-rw-r--r--test/Analysis/exceptions.mm2
-rw-r--r--test/Analysis/exercise-ps.c2
-rw-r--r--test/Analysis/explain-svals.c25
-rw-r--r--test/Analysis/explain-svals.cpp2
-rw-r--r--test/Analysis/explain-svals.m2
-rw-r--r--test/Analysis/expr-inspection.c4
-rw-r--r--test/Analysis/fields.c2
-rw-r--r--test/Analysis/free.c4
-rw-r--r--test/Analysis/func.c2
-rw-r--r--test/Analysis/generics.m4
-rw-r--r--test/Analysis/global-region-invalidation.c2
-rw-r--r--test/Analysis/global_region_invalidation.mm2
-rw-r--r--test/Analysis/gmalloc.c59
-rw-r--r--test/Analysis/gtest.cpp6
-rw-r--r--test/Analysis/html-diags-multifile.c2
-rw-r--r--test/Analysis/html-diags.c4
-rw-r--r--test/Analysis/identical-expressions.cpp2
-rw-r--r--test/Analysis/index-type.c4
-rw-r--r--test/Analysis/initializer.cpp2
-rw-r--r--test/Analysis/initializers-cfg-output.cpp2
-rw-r--r--test/Analysis/inline-not-supported.c2
-rw-r--r--test/Analysis/inline-plist.c20
-rw-r--r--test/Analysis/inline-unique-reports.c2
-rw-r--r--test/Analysis/inline.c2
-rw-r--r--test/Analysis/inline.cpp2
-rw-r--r--test/Analysis/inline2.c2
-rw-r--r--test/Analysis/inline3.c2
-rw-r--r--test/Analysis/inline4.c2
-rw-r--r--test/Analysis/inlining/DynDispatchBifurcate.m2
-rw-r--r--test/Analysis/inlining/InlineObjCClassMethod.m79
-rw-r--r--test/Analysis/inlining/InlineObjCInstanceMethod.m2
-rw-r--r--test/Analysis/inlining/ObjCDynTypePopagation.m2
-rw-r--r--test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m2
-rw-r--r--test/Analysis/inlining/RetainCountExamples.m2
-rw-r--r--test/Analysis/inlining/analysis-order.c2
-rw-r--r--test/Analysis/inlining/assume-super-init-does-not-return-nil.m2
-rw-r--r--test/Analysis/inlining/containers.cpp4
-rw-r--r--test/Analysis/inlining/dyn-dispatch-bifurcate.cpp2
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.c4
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.cpp4
-rw-r--r--test/Analysis/inlining/false-positive-suppression.c6
-rw-r--r--test/Analysis/inlining/false-positive-suppression.cpp4
-rw-r--r--test/Analysis/inlining/false-positive-suppression.m8
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.c2
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.cpp2
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.m2
-rw-r--r--test/Analysis/inlining/path-notes.c4
-rw-r--r--test/Analysis/inlining/path-notes.cpp4
-rw-r--r--test/Analysis/inlining/path-notes.m4
-rw-r--r--test/Analysis/inlining/retain-count-self-init.m2
-rw-r--r--test/Analysis/inlining/stl.cpp4
-rw-r--r--test/Analysis/inlining/test-always-inline-size-option.c2
-rw-r--r--test/Analysis/inlining/test_objc_inlining_option.m2
-rw-r--r--test/Analysis/iterator-past-end.cpp4
-rw-r--r--test/Analysis/ivars.m2
-rw-r--r--test/Analysis/keychainAPI-diagnostic-visitor.m2
-rw-r--r--test/Analysis/keychainAPI.m62
-rw-r--r--test/Analysis/kmalloc-linux.c2
-rw-r--r--test/Analysis/lambda-notes.cpp2
-rw-r--r--test/Analysis/lambdas-generalized-capture.cpp2
-rw-r--r--test/Analysis/lambdas.cpp6
-rw-r--r--test/Analysis/lambdas.mm2
-rw-r--r--test/Analysis/lifetime-extension.cpp2
-rw-r--r--test/Analysis/lit.local.cfg13
-rw-r--r--test/Analysis/live-variables.cpp2
-rw-r--r--test/Analysis/live-variables.m2
-rw-r--r--test/Analysis/localization-aggressive.m2
-rw-r--r--test/Analysis/localization.m2
-rw-r--r--test/Analysis/logical-ops.c2
-rw-r--r--test/Analysis/loop-widening.c2
-rw-r--r--test/Analysis/lvalue.cpp2
-rw-r--r--test/Analysis/malloc-annotations.c2
-rw-r--r--test/Analysis/malloc-custom.c2
-rw-r--r--test/Analysis/malloc-interprocedural.c2
-rw-r--r--test/Analysis/malloc-overflow.c2
-rw-r--r--test/Analysis/malloc-overflow.cpp2
-rw-r--r--test/Analysis/malloc-overflow2.c2
-rw-r--r--test/Analysis/malloc-plist.c2
-rw-r--r--test/Analysis/malloc-protoype.c2
-rw-r--r--test/Analysis/malloc-sizeof.c2
-rw-r--r--test/Analysis/malloc-sizeof.cpp2
-rw-r--r--test/Analysis/malloc-three-arg.c2
-rw-r--r--test/Analysis/malloc.c2
-rw-r--r--test/Analysis/malloc.cpp4
-rw-r--r--test/Analysis/malloc.m4
-rw-r--r--test/Analysis/malloc.mm2
-rw-r--r--test/Analysis/max-nodes-suppress-on-sink.c2
-rw-r--r--test/Analysis/member-expr.cpp2
-rw-r--r--test/Analysis/method-call-intra-p.cpp2
-rw-r--r--test/Analysis/method-call-path-notes.cpp4
-rw-r--r--test/Analysis/method-call.cpp2
-rw-r--r--test/Analysis/misc-ps-64.m2
-rw-r--r--test/Analysis/misc-ps-arm.m2
-rw-r--r--test/Analysis/misc-ps-cxx0x.cpp2
-rw-r--r--test/Analysis/misc-ps-eager-assume.m2
-rw-r--r--test/Analysis/misc-ps-ranges.m2
-rw-r--r--test/Analysis/misc-ps-region-store-i386.m2
-rw-r--r--test/Analysis/misc-ps-region-store-x86_64.m2
-rw-r--r--test/Analysis/misc-ps-region-store.cpp4
-rw-r--r--test/Analysis/misc-ps-region-store.m8
-rw-r--r--test/Analysis/misc-ps-region-store.mm4
-rw-r--r--test/Analysis/misc-ps.c2
-rw-r--r--test/Analysis/misc-ps.m8
-rw-r--r--test/Analysis/model-file.cpp2
-rw-r--r--test/Analysis/mpichecker.cpp2
-rw-r--r--test/Analysis/mpicheckernotes.cpp2
-rw-r--r--test/Analysis/new-with-exceptions.cpp4
-rw-r--r--test/Analysis/new.cpp2
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m2
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m6
-rw-r--r--test/Analysis/no-exit-cfg.c2
-rw-r--r--test/Analysis/no-outofbounds.c2
-rw-r--r--test/Analysis/no-unreachable-dtors.cpp2
-rw-r--r--test/Analysis/non-diagnosable-assumptions.c2
-rw-r--r--test/Analysis/nonnull.m2
-rw-r--r--test/Analysis/null-deref-path-notes.m4
-rw-r--r--test/Analysis/null-deref-ps-region.c2
-rw-r--r--test/Analysis/null-deref-ps.c6
-rw-r--r--test/Analysis/nullability-no-arc.mm2
-rw-r--r--test/Analysis/nullability.c2
-rw-r--r--test/Analysis/nullability.mm4
-rw-r--r--test/Analysis/nullability_nullonly.mm4
-rw-r--r--test/Analysis/nullptr.cpp4
-rw-r--r--test/Analysis/number-object-conversion.c4
-rw-r--r--test/Analysis/number-object-conversion.cpp4
-rw-r--r--test/Analysis/number-object-conversion.m8
-rw-r--r--test/Analysis/objc-arc.m2
-rw-r--r--test/Analysis/objc-bool.m2
-rw-r--r--test/Analysis/objc-boxing.m2
-rw-r--r--test/Analysis/objc-for.m2
-rw-r--r--test/Analysis/objc-message.m2
-rw-r--r--test/Analysis/objc-method-coverage.m2
-rw-r--r--test/Analysis/objc-properties.m2
-rw-r--r--test/Analysis/objc-radar17039661.m4
-rw-r--r--test/Analysis/objc-string.mm2
-rw-r--r--test/Analysis/objc-subscript.m2
-rw-r--r--test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m2
-rw-r--r--test/Analysis/objc_invalidation.m4
-rw-r--r--test/Analysis/openmp-unsupported.c7
-rw-r--r--test/Analysis/operator-calls.cpp2
-rw-r--r--test/Analysis/out-of-bounds-new.cpp2
-rw-r--r--test/Analysis/out-of-bounds.c2
-rw-r--r--test/Analysis/outofbound-notwork.c2
-rw-r--r--test/Analysis/outofbound.c2
-rw-r--r--test/Analysis/override-werror.c2
-rw-r--r--test/Analysis/padding_c.c2
-rw-r--r--test/Analysis/padding_cpp.cpp2
-rw-r--r--test/Analysis/padding_message.cpp2
-rw-r--r--test/Analysis/plist-html-macros.c4
-rw-r--r--test/Analysis/plist-macros.cpp4
-rw-r--r--test/Analysis/plist-output-alternate.m2
-rw-r--r--test/Analysis/plist-output.m206
-rw-r--r--test/Analysis/pointer-to-member.cpp2
-rw-r--r--test/Analysis/pr22954.c2
-rw-r--r--test/Analysis/pr4209.m2
-rw-r--r--test/Analysis/pr_2542_rdar_6793404.m2
-rw-r--r--test/Analysis/pr_4164.c2
-rw-r--r--test/Analysis/properties.m20
-rw-r--r--test/Analysis/properties.mm4
-rw-r--r--test/Analysis/pthreadlock.c2
-rw-r--r--test/Analysis/ptr-arith.c45
-rw-r--r--test/Analysis/ptr-arith.cpp2
-rw-r--r--test/Analysis/qt_malloc.cpp2
-rw-r--r--test/Analysis/range_casts.c2
-rw-r--r--test/Analysis/rdar-6442306-1.m2
-rw-r--r--test/Analysis/rdar-6540084.m2
-rw-r--r--test/Analysis/rdar-6541136-region.c2
-rw-r--r--test/Analysis/rdar-6562655.m2
-rw-r--r--test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m2
-rw-r--r--test/Analysis/rdar-7168531.m2
-rw-r--r--test/Analysis/redefined_system.c2
-rw-r--r--test/Analysis/refcnt_naming.m2
-rw-r--r--test/Analysis/reference.cpp16
-rw-r--r--test/Analysis/reference.mm2
-rw-r--r--test/Analysis/region-1.m2
-rw-r--r--test/Analysis/region-store.c2
-rw-r--r--test/Analysis/region-store.cpp2
-rw-r--r--test/Analysis/reinterpret-cast.cpp2
-rw-r--r--test/Analysis/retain-release-arc.m4
-rw-r--r--test/Analysis/retain-release-cache-out.m2
-rw-r--r--test/Analysis/retain-release-cf-audited.m4
-rw-r--r--test/Analysis/retain-release-gc-only.m2
-rw-r--r--test/Analysis/retain-release-inline.m2
-rw-r--r--test/Analysis/retain-release-path-notes-gc.m4
-rw-r--r--test/Analysis/retain-release-path-notes.m4
-rw-r--r--test/Analysis/retain-release-region-store.m2
-rw-r--r--test/Analysis/retain-release.m4
-rw-r--r--test/Analysis/retain-release.mm2
-rw-r--r--test/Analysis/return-ptr-range.cpp2
-rw-r--r--test/Analysis/security-syntax-checks-no-emit.c2
-rw-r--r--test/Analysis/security-syntax-checks.m16
-rw-r--r--test/Analysis/self-assign.cpp2
-rw-r--r--test/Analysis/self-init.m4
-rw-r--r--test/Analysis/shallow-mode.m2
-rw-r--r--test/Analysis/simple-stream-checks.c4
-rw-r--r--test/Analysis/sizeofpointer.c2
-rw-r--r--test/Analysis/stack-addr-ps.c2
-rw-r--r--test/Analysis/stack-addr-ps.cpp2
-rw-r--r--test/Analysis/stack-block-returned.cpp2
-rw-r--r--test/Analysis/stackaddrleak.c4
-rw-r--r--test/Analysis/static_local.m2
-rw-r--r--test/Analysis/stats.c2
-rw-r--r--test/Analysis/std-c-library-functions.c10
-rw-r--r--test/Analysis/std-c-library-functions.cpp2
-rw-r--r--test/Analysis/stream.c2
-rw-r--r--test/Analysis/string-fail.c4
-rw-r--r--test/Analysis/string.c8
-rw-r--r--test/Analysis/superclass.m2
-rw-r--r--test/Analysis/svalbuilder-logic.c2
-rw-r--r--test/Analysis/switch-case.c2
-rw-r--r--test/Analysis/symbol-reaper.c2
-rw-r--r--test/Analysis/taint-diagnostic-visitor.c13
-rw-r--r--test/Analysis/taint-generic.c39
-rw-r--r--test/Analysis/taint-tester.c2
-rw-r--r--test/Analysis/taint-tester.cpp2
-rw-r--r--test/Analysis/taint-tester.m2
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp4
-rw-r--r--test/Analysis/templates.cpp4
-rw-r--r--test/Analysis/temporaries-callback-order.cpp36
-rw-r--r--test/Analysis/temporaries.cpp43
-rw-r--r--test/Analysis/test-after-div-zero.c4
-rw-r--r--test/Analysis/test-include-cpp.cpp2
-rw-r--r--test/Analysis/test-include.c2
-rw-r--r--test/Analysis/test-objc-non-nil-return-value-checker.m2
-rw-r--r--test/Analysis/test-variably-modified-types.c2
-rw-r--r--test/Analysis/traversal-algorithm.mm2
-rw-r--r--test/Analysis/traversal-begin-end-function.c2
-rw-r--r--test/Analysis/traversal-path-unification.c4
-rw-r--r--test/Analysis/ubigraph-viz.cpp2
-rw-r--r--test/Analysis/undef-buffers.c2
-rw-r--r--test/Analysis/uninit-const.c62
-rw-r--r--test/Analysis/uninit-const.cpp26
-rw-r--r--test/Analysis/uninit-msg-expr.m4
-rw-r--r--test/Analysis/uninit-ps-rdar6145427.m2
-rw-r--r--test/Analysis/uninit-vals-ps-region.m2
-rw-r--r--test/Analysis/uninit-vals-ps.c10
-rw-r--r--test/Analysis/uninit-vals-union.c2
-rw-r--r--test/Analysis/uninit-vals.cpp6
-rw-r--r--test/Analysis/uninit-vals.m2
-rw-r--r--test/Analysis/unions-region.m2
-rw-r--r--test/Analysis/unions.cpp2
-rw-r--r--test/Analysis/unix-api.c2
-rw-r--r--test/Analysis/unix-api.cpp2
-rw-r--r--test/Analysis/unix-fns.c4
-rw-r--r--test/Analysis/unreachable-code-path.c2
-rw-r--r--test/Analysis/unsupported-types.c31
-rw-r--r--test/Analysis/unused-ivars.m2
-rw-r--r--test/Analysis/valist-as-lazycompound.c21
-rw-r--r--test/Analysis/valist-uninitialized-no-undef.c40
-rw-r--r--test/Analysis/valist-uninitialized.c96
-rw-r--r--test/Analysis/valist-unterminated.c72
-rw-r--r--test/Analysis/variadic-method-types.m2
-rw-r--r--test/Analysis/vfork.c4
-rw-r--r--test/Analysis/virtualcall.cpp6
-rw-r--r--test/Analysis/vla.c2
-rw-r--r--test/Analysis/weak-functions.c2
-rw-r--r--test/CMakeLists.txt14
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp93
-rw-r--r--test/CXX/class.derived/class.abstract/p16.cpp8
-rw-r--r--test/CXX/class.derived/class.member.lookup/p10.cpp114
-rw-r--r--test/CXX/class.derived/class.member.lookup/p6.cpp10
-rw-r--r--test/CXX/class.derived/class.member.lookup/p7.cpp10
-rw-r--r--test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp65
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp37
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp10
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1z.cpp8
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp14
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp35
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp18
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp45
-rw-r--r--test/CXX/drs/dr10xx.cpp24
-rw-r--r--test/CXX/drs/dr12xx.cpp20
-rw-r--r--test/CXX/drs/dr13xx.cpp99
-rw-r--r--test/CXX/drs/dr16xx.cpp118
-rw-r--r--test/CXX/drs/dr1xx.cpp6
-rw-r--r--test/CXX/drs/dr21xx.cpp24
-rw-r--r--test/CXX/drs/dr2xx.cpp8
-rw-r--r--test/CXX/drs/dr3xx.cpp13
-rw-r--r--test/CXX/drs/dr4xx.cpp4
-rw-r--r--test/CXX/drs/dr5xx.cpp18
-rw-r--r--test/CXX/expr/expr.post/expr.type.conv/p1.cpp10
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp2
-rw-r--r--test/CXX/over/over.match/over.match.best/p1.cpp24
-rw-r--r--test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp25
-rw-r--r--test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp41
-rw-r--r--test/CXX/special/class.dtor/p10-0x.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp2
-rw-r--r--test/CXX/temp/temp.deduct.guide/p1.cpp108
-rw-r--r--test/CXX/temp/temp.deduct.guide/p2.cpp15
-rw-r--r--test/CXX/temp/temp.deduct.guide/p3.cpp72
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp53
-rw-r--r--test/CXX/temp/temp.res/p3.cpp38
-rw-r--r--test/CXX/temp/temp.res/temp.local/p1.cpp57
-rw-r--r--test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp2
-rw-r--r--test/CodeCompletion/auto_type.c5
-rw-r--r--test/CodeCompletion/keywords.cpp79
-rw-r--r--test/CodeCompletion/member-access.cpp14
-rw-r--r--test/CodeCompletion/ordinary-name-cxx11.cpp9
-rw-r--r--test/CodeCompletion/pragma-macro-token-caching.c18
-rw-r--r--test/CodeGen/2006-05-19-SingleEltReturn.c11
-rw-r--r--test/CodeGen/Inputs/debug-info-macro.h12
-rw-r--r--test/CodeGen/Inputs/pgo-sample-thinlto-summary.prof4
-rw-r--r--test/CodeGen/aarch64-neon-intrinsics.c2
-rw-r--r--test/CodeGen/address-space.c13
-rw-r--r--test/CodeGen/alloc-align-attr.c101
-rw-r--r--test/CodeGen/alloc-size.c2
-rw-r--r--test/CodeGen/altivec.c2
-rw-r--r--test/CodeGen/avr-inline-asm-constraints.c124
-rw-r--r--test/CodeGen/avr-unsupported-inline-asm-constraints.c8
-rw-r--r--test/CodeGen/avr/attributes/interrupt.c6
-rw-r--r--test/CodeGen/avr/attributes/signal.c6
-rw-r--r--test/CodeGen/avr/target-cpu-defines/atmega328p.c7
-rw-r--r--test/CodeGen/avr/target-cpu-defines/attiny104.c7
-rw-r--r--test/CodeGen/avr/target-cpu-defines/common.c6
-rw-r--r--test/CodeGen/avx-builtins.c28
-rw-r--r--test/CodeGen/avx2-builtins.c36
-rw-r--r--test/CodeGen/avx512-reduceMinMaxIntrin.c10
-rw-r--r--test/CodeGen/avx512bw-builtins.c56
-rw-r--r--test/CodeGen/avx512dq-builtins.c105
-rw-r--r--test/CodeGen/avx512f-builtins.c295
-rw-r--r--test/CodeGen/avx512pf-builtins.c32
-rw-r--r--test/CodeGen/avx512vl-builtins.c62
-rw-r--r--test/CodeGen/avx512vlbw-builtins.c12
-rw-r--r--test/CodeGen/avx512vldq-builtins.c67
-rw-r--r--test/CodeGen/blocks.c34
-rw-r--r--test/CodeGen/builtin-clflushopt.c2
-rw-r--r--test/CodeGen/builtin-clzero.c9
-rw-r--r--test/CodeGen/builtins-mips-msa-error.c14
-rw-r--r--test/CodeGen/builtins-mips-msa.c7
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c42
-rw-r--r--test/CodeGen/builtins-ppc-crypto-disabled.c6
-rw-r--r--test/CodeGen/builtins-ppc-crypto.c4
-rw-r--r--test/CodeGen/builtins-ppc-error.c4
-rw-r--r--test/CodeGen/builtins-ppc-htm.c2
-rw-r--r--test/CodeGen/builtins-ppc-p8vector.c6
-rw-r--r--test/CodeGen/builtins-ppc-p9vector.c4
-rw-r--r--test/CodeGen/builtins-ppc-quadword.c6
-rw-r--r--test/CodeGen/builtins-ppc-vsx.c4
-rw-r--r--test/CodeGen/builtins-wasm.c8
-rw-r--r--test/CodeGen/builtins-x86.c5
-rw-r--r--test/CodeGen/catch-undef-behavior.c21
-rw-r--r--test/CodeGen/cfi-check-fail.c5
-rw-r--r--test/CodeGen/cleanup-destslot-simple.c8
-rw-r--r--test/CodeGen/compound-assign-overflow.c4
-rw-r--r--test/CodeGen/debug-info-macro.c57
-rw-r--r--test/CodeGen/default-address-space.c58
-rw-r--r--test/CodeGen/fentry.c11
-rw-r--r--test/CodeGen/ffp-contract-fast-option.cpp29
-rw-r--r--test/CodeGen/ffp-contract-option.c6
-rw-r--r--test/CodeGen/fp-contract-fast-pragma.cpp69
-rw-r--r--test/CodeGen/fp-contract-on-pragma.cpp76
-rw-r--r--test/CodeGen/function-sections.c8
-rw-r--r--test/CodeGen/libcall-declarations.c15
-rw-r--r--test/CodeGen/lifetime-asan.c8
-rw-r--r--test/CodeGen/lifetime2.c52
-rw-r--r--test/CodeGen/mmx-builtins.c87
-rw-r--r--test/CodeGen/ms-declspecs.c2
-rw-r--r--test/CodeGen/ms-inline-asm-EVEN.c16
-rw-r--r--test/CodeGen/ms-inline-asm.c21
-rw-r--r--test/CodeGen/ms-intrinsics.c39
-rw-r--r--test/CodeGen/ms-x86-intrinsics.c65
-rw-r--r--test/CodeGen/object-size.c110
-rw-r--r--test/CodeGen/object-size.cpp14
-rw-r--r--test/CodeGen/opt-record-MIR.c33
-rw-r--r--test/CodeGen/pass-object-size.c57
-rw-r--r--test/CodeGen/pgo-sample-thinlto-summary.c42
-rw-r--r--test/CodeGen/ppc64-align-struct.c2
-rw-r--r--test/CodeGen/ppc64-complex-parms.c2
-rw-r--r--test/CodeGen/ppc64-vector.c2
-rw-r--r--test/CodeGen/ppc64le-aggregates.c2
-rw-r--r--test/CodeGen/pr3997.c13
-rw-r--r--test/CodeGen/sanitize-init-order.cpp4
-rw-r--r--test/CodeGen/sanitize-recover.c15
-rw-r--r--test/CodeGen/sanitize-thread-no-checking-at-run-time.m15
-rw-r--r--test/CodeGen/sse-builtins.c2
-rw-r--r--test/CodeGen/sse2-builtins.c4
-rw-r--r--test/CodeGen/sse41-builtins.c2
-rw-r--r--test/CodeGen/temporary-lifetime-exceptions.cpp12
-rw-r--r--test/CodeGen/temporary-lifetime.cpp48
-rw-r--r--test/CodeGen/thin_link_bitcode.c9
-rw-r--r--test/CodeGen/thinlto-emit-llvm.c10
-rw-r--r--test/CodeGen/thinlto-multi-module.ll22
-rw-r--r--test/CodeGen/transparent-union.c11
-rw-r--r--test/CodeGen/ubsan-promoted-arith.cpp131
-rw-r--r--test/CodeGen/ubsan-shift.c47
-rw-r--r--test/CodeGen/unaligned-decl.c22
-rw-r--r--test/CodeGen/unaligned-expr.c217
-rw-r--r--test/CodeGen/unaligned-field.c17
-rw-r--r--test/CodeGen/unsigned-promotion.c113
-rw-r--r--test/CodeGen/xop-builtins-cmp.c405
-rw-r--r--test/CodeGen/xop-builtins.c10
-rw-r--r--test/CodeGen/xray-always-instrument.cpp15
-rw-r--r--test/CodeGen/xray-attributes-supported-arm.cpp13
-rw-r--r--test/CodeGen/xray-attributes-supported.cpp6
-rw-r--r--test/CodeGen/xray-instruction-threshold.cpp14
-rw-r--r--test/CodeGen/xray-log-args.cpp13
-rw-r--r--test/CodeGen/zvector.c4502
-rw-r--r--test/CodeGenCUDA/fp-contract.cu4
-rw-r--r--test/CodeGenCUDA/propagate-metadata.cu62
-rw-r--r--test/CodeGenCXX/atomic-dllexport.cpp9
-rw-r--r--test/CodeGenCXX/cfi-ms-rtti.cpp4
-rw-r--r--test/CodeGenCXX/constructors.cpp56
-rw-r--r--test/CodeGenCXX/cxx11-initializer-aggregate.cpp15
-rw-r--r--test/CodeGenCXX/debug-info-class-optzns.cpp26
-rw-r--r--test/CodeGenCXX/debug-info-inheriting-constructor.cpp25
-rw-r--r--test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp14
-rw-r--r--test/CodeGenCXX/debug-info-template-deduction-guide.cpp17
-rw-r--r--test/CodeGenCXX/debug-info-use-after-free.cpp3
-rw-r--r--test/CodeGenCXX/destructors.cpp14
-rw-r--r--test/CodeGenCXX/dllexport.cpp6
-rw-r--r--test/CodeGenCXX/dllimport.cpp29
-rw-r--r--test/CodeGenCXX/dynamic-cast-hint.cpp6
-rw-r--r--test/CodeGenCXX/exceptions-cxx-new.cpp4
-rw-r--r--test/CodeGenCXX/exceptions-seh.cpp6
-rw-r--r--test/CodeGenCXX/explicit-instantiation.cpp17
-rw-r--r--test/CodeGenCXX/float128-declarations.cpp4
-rw-r--r--test/CodeGenCXX/global-init.cpp2
-rw-r--r--test/CodeGenCXX/implicit-exception-spec.cpp22
-rw-r--r--test/CodeGenCXX/inheriting-constructor.cpp16
-rw-r--r--test/CodeGenCXX/initializer-list-ctor-order.cpp29
-rw-r--r--test/CodeGenCXX/linetable-cleanup.cpp4
-rw-r--r--test/CodeGenCXX/lpad-linetable.cpp2
-rw-r--r--test/CodeGenCXX/mangle-unnamed.cpp4
-rw-r--r--test/CodeGenCXX/mangle.cpp12
-rw-r--r--test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp2
-rw-r--r--test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp6
-rw-r--r--test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp10
-rw-r--r--test/CodeGenCXX/microsoft-abi-structors.cpp10
-rw-r--r--test/CodeGenCXX/microsoft-abi-throw.cpp2
-rw-r--r--test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp6
-rw-r--r--test/CodeGenCXX/modules-ts.cppm5
-rw-r--r--test/CodeGenCXX/new-array-init.cpp7
-rw-r--r--test/CodeGenCXX/no-lto-unit.cpp13
-rw-r--r--test/CodeGenCXX/nrvo.cpp4
-rw-r--r--test/CodeGenCXX/optnone-class-members.cpp2
-rw-r--r--test/CodeGenCXX/optnone-def-decl.cpp2
-rw-r--r--test/CodeGenCXX/reference-init.cpp13
-rw-r--r--test/CodeGenCXX/regcall.cpp4
-rw-r--r--test/CodeGenCXX/static-init.cpp8
-rw-r--r--test/CodeGenCXX/stmtexpr.cpp82
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp39
-rw-r--r--test/CodeGenCXX/type-metadata-thinlto.cpp11
-rw-r--r--test/CodeGenCXX/type-metadata.cpp16
-rw-r--r--test/CodeGenCXX/ubsan-bitfields.cpp34
-rw-r--r--test/CodeGenCXX/ubsan-global-alignment.cpp29
-rw-r--r--test/CodeGenCXX/ubsan-suppress-checks.cpp221
-rw-r--r--test/CodeGenCXX/ubsan-type-checks.cpp36
-rw-r--r--test/CodeGenCXX/unaligned.cpp6
-rw-r--r--test/CodeGenCXX/volatile-1.cpp34
-rw-r--r--test/CodeGenCXX/volatile.cpp4
-rw-r--r--test/CodeGenCoroutines/coro-alloc.cpp60
-rw-r--r--test/CodeGenCoroutines/coro-await.cpp230
-rw-r--r--test/CodeGenCoroutines/coro-builtins.c2
-rw-r--r--test/CodeGenCoroutines/coro-cleanup.cpp74
-rw-r--r--test/CodeGenCoroutines/coro-eh-cleanup.cpp74
-rw-r--r--test/CodeGenCoroutines/coro-return.cpp59
-rw-r--r--test/CodeGenObjC/arc-blocks.m57
-rw-r--r--test/CodeGenObjC/arc-linetable-autorelease.m5
-rw-r--r--test/CodeGenObjC/arc-precise-lifetime.m68
-rw-r--r--test/CodeGenObjC/arc-ternary-op.m12
-rw-r--r--test/CodeGenObjC/arc.m126
-rw-r--r--test/CodeGenObjC/availability-cf-link-guard.m45
-rw-r--r--test/CodeGenObjC/availability-check.m31
-rw-r--r--test/CodeGenObjC/empty-collection-literals.m51
-rw-r--r--test/CodeGenObjC/exceptions.m4
-rw-r--r--test/CodeGenObjC/ivar-type-encoding.m35
-rw-r--r--test/CodeGenObjC/ubsan-bool.m57
-rw-r--r--test/CodeGenObjC/ubsan-nonnull-and-nullability.m31
-rw-r--r--test/CodeGenObjC/ubsan-nonnull.m48
-rw-r--r--test/CodeGenObjC/ubsan-nullability.m182
-rw-r--r--test/CodeGenObjCXX/arc-attrs-abi.mm38
-rw-r--r--test/CodeGenObjCXX/arc-blocks.mm2
-rw-r--r--test/CodeGenObjCXX/arc-move.mm8
-rw-r--r--test/CodeGenObjCXX/arc-references.mm10
-rw-r--r--test/CodeGenObjCXX/arc.mm6
-rw-r--r--test/CodeGenObjCXX/encode.mm2
-rw-r--r--test/CodeGenObjCXX/lambda-expressions.mm13
-rw-r--r--test/CodeGenObjCXX/lambda-to-block.mm18
-rw-r--r--test/CodeGenObjCXX/literals.mm10
-rw-r--r--test/CodeGenObjCXX/objc-weak.mm69
-rw-r--r--test/CodeGenObjCXX/objfw-exceptions.mm17
-rw-r--r--test/CodeGenOpenCL/address-space-constant-initializers.cl2
-rw-r--r--test/CodeGenOpenCL/address-spaces.cl31
-rw-r--r--test/CodeGenOpenCL/amdgcn-large-globals.cl12
-rw-r--r--test/CodeGenOpenCL/amdgpu-alignment.cl522
-rw-r--r--test/CodeGenOpenCL/amdgpu-attrs.cl12
-rw-r--r--test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl125
-rw-r--r--test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl131
-rw-r--r--test/CodeGenOpenCL/amdgpu-env-amdgiz.cl9
-rw-r--r--test/CodeGenOpenCL/amdgpu-nullptr.cl194
-rw-r--r--test/CodeGenOpenCL/blocks.cl17
-rw-r--r--test/CodeGenOpenCL/builtins-amdgcn-gfx9.cl11
-rw-r--r--test/CodeGenOpenCL/builtins-amdgcn-vi.cl8
-rw-r--r--test/CodeGenOpenCL/builtins-amdgcn.cl95
-rw-r--r--test/CodeGenOpenCL/cl20-device-side-enqueue.cl58
-rw-r--r--test/CodeGenOpenCL/denorms-are-zero.cl10
-rw-r--r--test/CodeGenOpenCL/gfx9-fp32-denorms.cl13
-rw-r--r--test/CodeGenOpenCL/kernel-arg-info.cl13
-rw-r--r--test/CodeGenOpenCL/overload.cl46
-rw-r--r--test/CodeGenOpenCL/preserve_vec3.cl24
-rw-r--r--test/CodeGenOpenCL/relaxed-fpmath.cl29
-rw-r--r--test/CodeGenOpenCL/sampler.cl4
-rw-r--r--test/CodeGenOpenCL/vla.cl12
-rw-r--r--test/CoverageMapping/implicit-def-in-macro.m2
-rw-r--r--test/CoverageMapping/macro-expressions.cpp2
-rw-r--r--test/CoverageMapping/objc.m2
-rw-r--r--test/CoverageMapping/unused_names.c13
-rw-r--r--test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/aarch64/.keep0
-rw-r--r--test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/arm/.keep0
-rw-r--r--test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/i386/.keep0
-rw-r--r--test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64/.keep0
-rw-r--r--test/Driver/XRay/xray-instrument-cpu.c2
-rw-r--r--test/Driver/aarch64-cpus.c52
-rw-r--r--test/Driver/arch-specific-libdir-rpath.c85
-rw-r--r--test/Driver/arch-specific-libdir.c53
-rw-r--r--test/Driver/arm-abi.c4
-rw-r--r--test/Driver/arm-cortex-cpus.c6
-rw-r--r--test/Driver/arm-execute-only.c4
-rw-r--r--test/Driver/arm-no-neg-immediates.c8
-rw-r--r--test/Driver/cl-link-at-file.c1
-rw-r--r--test/Driver/cl-link.c9
-rw-r--r--test/Driver/cl-options.c15
-rw-r--r--test/Driver/clang_f_opts.c12
-rw-r--r--test/Driver/crash-report-crashfile.m33
-rw-r--r--test/Driver/cuda-no-stack-protector.cu23
-rw-r--r--test/Driver/darwin-ld-pthread.c4
-rw-r--r--test/Driver/darwin-simulator-macro.c12
-rw-r--r--test/Driver/debug-options.c31
-rw-r--r--test/Driver/embed-bitcode.c11
-rw-r--r--test/Driver/fast-math.c21
-rw-r--r--test/Driver/frame-pointer-elim.c4
-rw-r--r--test/Driver/frame-pointer.c7
-rw-r--r--test/Driver/fsanitize.c35
-rw-r--r--test/Driver/fuchsia.c5
-rw-r--r--test/Driver/hexagon-toolchain-elf.c8
-rw-r--r--test/Driver/immediate-options.c5
-rw-r--r--test/Driver/include-default-header.cl6
-rw-r--r--test/Driver/linux-ld.c8
-rw-r--r--test/Driver/lto-unit.c7
-rw-r--r--test/Driver/mglobal-merge.c4
-rw-r--r--test/Driver/mingw.cpp12
-rw-r--r--test/Driver/mips-as.c79
-rw-r--r--test/Driver/msc-version.c2
-rw-r--r--test/Driver/no-arc-exception-silence.m2
-rw-r--r--test/Driver/openbsd.c11
-rw-r--r--test/Driver/pic.c4
-rw-r--r--test/Driver/ppc-features.cpp55
-rw-r--r--test/Driver/r600-mcpu.cl4
-rw-r--r--test/Driver/reloc-model.c4
-rw-r--r--test/Driver/response-file.c9
-rw-r--r--test/Driver/sanitizer-ld.c2
-rw-r--r--test/Driver/unknown-std.S2
-rw-r--r--test/Driver/unknown-std.c34
-rw-r--r--test/Driver/unknown-std.cl16
-rw-r--r--test/Driver/unknown-std.cpp26
-rw-r--r--test/Driver/unsupported-faltivec.c10
-rw-r--r--test/Driver/windows-cross.c10
-rw-r--r--test/Driver/x86-target-features.c35
-rw-r--r--test/FixIt/fixit.cpp11
-rw-r--r--test/FixIt/no-fixit.cpp12
-rw-r--r--test/Format/inplace.cpp264
-rw-r--r--test/Format/style-on-command-line.cpp23
-rw-r--r--test/Frontend/aarch64-target-cpu.c2
-rw-r--r--test/Frontend/gnu-mcount.c7
-rw-r--r--test/Frontend/iframework.c1
-rw-r--r--test/Frontend/objc-bool-is-bool.m6
-rw-r--r--test/Frontend/optimization-remark-with-hotness.c8
-rw-r--r--test/Frontend/optimization-remark.c6
-rw-r--r--test/Frontend/preprocessed-input.i10
-rw-r--r--test/Headers/Inputs/usr/include/math.h1
-rw-r--r--test/Headers/Inputs/usr/include/tgmath.h4
-rw-r--r--test/Headers/altivec-header.c8
-rw-r--r--test/Headers/altivec-intrin.c2
-rw-r--r--test/Headers/htm-header.c19
-rw-r--r--test/Headers/opencl-c-header.cl43
-rw-r--r--test/Headers/stdarg-gnuc_va_list.c10
-rw-r--r--test/Headers/tgmath-darwin.c12
-rw-r--r--test/Import/forward-declared-struct/Inputs/S1.c1
-rw-r--r--test/Import/forward-declared-struct/Inputs/S2.c3
-rw-r--r--test/Import/forward-declared-struct/test.c5
-rw-r--r--test/Import/member-in-struct/Inputs/S.c3
-rw-r--r--test/Import/member-in-struct/test.c5
-rw-r--r--test/Import/multiple-forward-declarations/Inputs/S1.c1
-rw-r--r--test/Import/multiple-forward-declarations/Inputs/S2.c1
-rw-r--r--test/Import/multiple-forward-declarations/test.c4
-rw-r--r--test/Import/overloaded-function/Inputs/F1.c1
-rw-r--r--test/Import/overloaded-function/Inputs/F2.c4
-rw-r--r--test/Import/overloaded-function/test.c7
-rw-r--r--test/Import/struct-in-namespace/Inputs/N1.cpp11
-rw-r--r--test/Import/struct-in-namespace/Inputs/N2.cpp5
-rw-r--r--test/Import/struct-in-namespace/Inputs/N3.cpp5
-rw-r--r--test/Import/struct-in-namespace/test.cpp7
-rw-r--r--test/Import/template-specialization/Inputs/T.cpp14
-rw-r--r--test/Import/template-specialization/test.cpp7
-rw-r--r--test/Index/Core/Inputs/sys/system-head.h36
-rw-r--r--test/Index/Core/index-pch.c13
-rw-r--r--test/Index/Core/index-source.cpp48
-rw-r--r--test/Index/Core/index-source.m264
-rw-r--r--test/Index/Core/index-subkinds.m6
-rw-r--r--test/Index/Core/index-system.mm3
-rw-r--r--test/Index/Core/index-with-module.m8
-rw-r--r--test/Index/annotate-nested-name-specifier.cpp40
-rw-r--r--test/Index/comment-cplus-decls.cpp16
-rw-r--r--test/Index/complete-block-properties.m10
-rw-r--r--test/Index/complete-cached-globals.cpp25
-rw-r--r--test/Index/complete-objc-message.m51
-rw-r--r--test/Index/complete-preamble.h5
-rw-r--r--test/Index/crash-recovery-code-complete.c1
-rw-r--r--test/Index/crash-recovery-modules.m3
-rw-r--r--test/Index/crash-recovery-reparse.c1
-rw-r--r--test/Index/crash-recovery.c1
-rw-r--r--test/Index/file-refs.cpp4
-rw-r--r--test/Index/get-cursor.m33
-rw-r--r--test/Index/index-decls.m2
-rw-r--r--test/Index/opencl-types.cl24
-rw-r--r--test/Index/overriding-ftemplate-comments.cpp2
-rw-r--r--test/Index/overriding-method-comments.mm2
-rw-r--r--test/Index/pch-from-libclang.c27
-rw-r--r--test/Index/print-type.cpp140
-rw-r--r--test/Index/recursive-cxx-member-calls.cpp4
-rw-r--r--test/Layout/ms-x86-basic-layout.cpp4
-rw-r--r--test/Lexer/asm-preproc-no-unicode.s8
-rwxr-xr-xtest/Lexer/case-insensitive-include-pr31836.sh9
-rw-r--r--test/Lexer/cxx-features.cpp12
-rw-r--r--test/Misc/ast-dump-attr.cpp47
-rw-r--r--test/Misc/ast-dump-decl.cpp8
-rw-r--r--test/Misc/ast-dump-decl.m4
-rw-r--r--test/Misc/ast-dump-templates.cpp10
-rw-r--r--test/Misc/ast-print-out-of-line-func.cpp54
-rw-r--r--test/Misc/backend-stack-frame-diagnostics.cpp2
-rw-r--r--test/Misc/diag-template-diffing.cpp8
-rw-r--r--test/Modules/ExtDebugInfo.cpp2
-rw-r--r--test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/Headers/B.h1
-rw-r--r--test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/Headers/Sub.h2
-rw-r--r--test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/PrivateHeaders/BPriv.h1
-rw-r--r--test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h1
-rw-r--r--test/Modules/Inputs/Main.framework/Headers/A.h1
-rw-r--r--test/Modules/Inputs/Main.framework/Headers/Main.h2
-rw-r--r--test/Modules/Inputs/Main.framework/Modules/module.modulemap12
-rw-r--r--test/Modules/Inputs/Main.framework/Modules/module.private.modulemap11
-rw-r--r--test/Modules/Inputs/Main.framework/PrivateHeaders/APriv.h1
-rw-r--r--test/Modules/Inputs/Main.framework/PrivateHeaders/MainPriv.h1
-rw-r--r--test/Modules/Inputs/anon-redecl/a.h2
-rw-r--r--test/Modules/Inputs/anon-redecl/b.h2
-rw-r--r--test/Modules/Inputs/anon-redecl/c1.h2
-rw-r--r--test/Modules/Inputs/anon-redecl/c2.h2
-rw-r--r--test/Modules/Inputs/anon-redecl/module.modulemap6
-rw-r--r--test/Modules/Inputs/category_right_sub.h5
-rw-r--r--test/Modules/Inputs/codegen-flags/foo.h4
-rw-r--r--test/Modules/Inputs/codegen-flags/foo.modulemap1
-rw-r--r--test/Modules/Inputs/codegen-flags/use.cpp5
-rw-r--r--test/Modules/Inputs/codegen-nodep/foo.h11
-rw-r--r--test/Modules/Inputs/codegen-nodep/foo.modulemap1
-rw-r--r--test/Modules/Inputs/codegen-opt/bar.h2
-rw-r--r--test/Modules/Inputs/codegen-opt/bar.modulemap1
-rw-r--r--test/Modules/Inputs/codegen-opt/foo.h10
-rw-r--r--test/Modules/Inputs/codegen-opt/foo.modulemap1
-rw-r--r--test/Modules/Inputs/codegen-opt/use.cpp2
-rw-r--r--test/Modules/Inputs/codegen/foo.h32
-rw-r--r--test/Modules/Inputs/codegen/foo.modulemap1
-rw-r--r--test/Modules/Inputs/codegen/use.cpp8
-rw-r--r--test/Modules/Inputs/cxx17/decls.h3
-rw-r--r--test/Modules/Inputs/cxx17/module.modulemap1
-rw-r--r--test/Modules/Inputs/diag_pragma.h10
-rw-r--r--test/Modules/Inputs/gnumode-non-benign/module.h5
-rw-r--r--test/Modules/Inputs/gnumode-non-benign/module.modulemap1
-rw-r--r--test/Modules/Inputs/hidden-names/hidden.h3
-rw-r--r--test/Modules/Inputs/hidden-names/module.modulemap4
-rw-r--r--test/Modules/Inputs/hidden-names/visible.h2
-rw-r--r--test/Modules/Inputs/implicit-built-Werror-using-W/convert.h8
-rw-r--r--test/Modules/Inputs/implicit-built-Werror-using-W/module.modulemap3
-rw-r--r--test/Modules/Inputs/invalid-module-id/NC-Prefix.pch3
-rw-r--r--test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NC.h1
-rw-r--r--test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NU-Visibility.h1
-rw-r--r--test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NUGeometry.h1
-rw-r--r--test/Modules/Inputs/invalid-module-id/NC.framework/Modules/module.modulemap6
-rw-r--r--test/Modules/Inputs/invalid-module-id/NC.framework/Modules/module.private.modulemap5
-rw-r--r--test/Modules/Inputs/invalid-module-id/NC.framework/PrivateHeaders/NUAssert.h1
-rw-r--r--test/Modules/Inputs/invalid-module-id/NC.framework/PrivateHeaders/NULog.h1
-rw-r--r--test/Modules/Inputs/merge-function-defs/a.h4
-rw-r--r--test/Modules/Inputs/merge-function-defs/b.h0
-rw-r--r--test/Modules/Inputs/merge-function-defs/map4
-rw-r--r--test/Modules/Inputs/merge-name-for-linkage/b.h4
-rw-r--r--test/Modules/Inputs/merge-name-for-linkage/c1.h1
-rw-r--r--test/Modules/Inputs/merge-name-for-linkage/c2.h2
-rw-r--r--test/Modules/Inputs/merge-name-for-linkage/module.modulemap1
-rw-r--r--test/Modules/Inputs/merge-using-decls/b.h6
-rw-r--r--test/Modules/Inputs/module.map5
-rw-r--r--test/Modules/Inputs/outofdate-rebuild/AppKit.h3
-rw-r--r--test/Modules/Inputs/outofdate-rebuild/Cocoa.h5
-rw-r--r--test/Modules/Inputs/outofdate-rebuild/CoreText.h1
-rw-r--r--test/Modules/Inputs/outofdate-rebuild/CoreVideo.h3
-rw-r--r--test/Modules/Inputs/outofdate-rebuild/Foundation.h3
-rw-r--r--test/Modules/Inputs/outofdate-rebuild/module.modulemap19
-rw-r--r--test/Modules/Inputs/overloadable-attrs/a.h28
-rw-r--r--test/Modules/Inputs/overloadable-attrs/module.modulemap3
-rw-r--r--test/Modules/Inputs/pragma_pack_set.h3
-rw-r--r--test/Modules/Inputs/system-out-of-date/X.h2
-rw-r--r--test/Modules/Inputs/system-out-of-date/Y.h1
-rw-r--r--test/Modules/Inputs/system-out-of-date/Z.h2
-rw-r--r--test/Modules/Inputs/system-out-of-date/module.map12
-rw-r--r--test/Modules/Inputs/warning-mismatch/Mismatch.h1
-rw-r--r--test/Modules/Inputs/warning-mismatch/System.h2
-rw-r--r--test/Modules/Inputs/warning-mismatch/module.modulemap7
-rw-r--r--test/Modules/anon-redecl.cpp15
-rw-r--r--test/Modules/builtins.m1
-rw-r--r--test/Modules/codegen-flags.test25
-rw-r--r--test/Modules/codegen-nodep.test13
-rw-r--r--test/Modules/codegen-opt.test65
-rw-r--r--test/Modules/codegen.test49
-rw-r--r--test/Modules/cxx-templates.cpp10
-rw-r--r--test/Modules/cxx17.cpp11
-rw-r--r--test/Modules/dependency-dump-dependent-module.m2
-rw-r--r--test/Modules/dependency-dump.m2
-rw-r--r--test/Modules/diag-pragma.cpp47
-rw-r--r--test/Modules/diagnostic-options-out-of-date.m10
-rw-r--r--test/Modules/find-privateheaders.m2
-rw-r--r--test/Modules/gnumode-non-benign.cpp11
-rw-r--r--test/Modules/hidden-names.cpp13
-rw-r--r--test/Modules/implicit-built-Werror-using-W.cpp42
-rw-r--r--test/Modules/implicit-private-with-different-name.m2
-rw-r--r--test/Modules/invalid-pch-module-id.m13
-rw-r--r--test/Modules/localsubmodulevis.m8
-rw-r--r--test/Modules/merge-function-defs.cpp11
-rw-r--r--test/Modules/merge-name-for-linkage.cpp1
-rw-r--r--test/Modules/merge-using-decls.cpp13
-rw-r--r--test/Modules/module-impl-with-link.c2
-rw-r--r--test/Modules/module_file_info.m11
-rw-r--r--test/Modules/module_map_cwd.c9
-rw-r--r--test/Modules/modules-cache-path-canonicalization.m30
-rw-r--r--test/Modules/objc-categories.m6
-rw-r--r--test/Modules/odr_hash.cpp953
-rw-r--r--test/Modules/outofdate-rebuild.m15
-rw-r--r--test/Modules/overloadable-attrs.cpp22
-rw-r--r--test/Modules/pragma-pack.cpp25
-rw-r--r--test/Modules/rebuild.m8
-rw-r--r--test/Modules/system-out-of-date-test.m17
-rw-r--r--test/Modules/system_version.m31
-rw-r--r--test/Modules/warning-mismatch.m13
-rw-r--r--test/OpenMP/cancel_messages.cpp8
-rw-r--r--test/OpenMP/cancellation_point_messages.cpp8
-rw-r--r--test/OpenMP/declare_reduction_messages.cpp14
-rw-r--r--test/OpenMP/distribute_collapse_messages.cpp26
-rw-r--r--test/OpenMP/distribute_firstprivate_codegen.cpp382
-rw-r--r--test/OpenMP/distribute_lastprivate_codegen.cpp2
-rw-r--r--test/OpenMP/linking.c16
-rw-r--r--test/OpenMP/nvptx_target_codegen.cpp32
-rw-r--r--test/OpenMP/nvptx_target_parallel_codegen.cpp136
-rw-r--r--test/OpenMP/nvptx_target_parallel_num_threads_codegen.cpp126
-rw-r--r--test/OpenMP/nvptx_target_parallel_proc_bind_codegen.cpp106
-rw-r--r--test/OpenMP/nvptx_target_parallel_reduction_codegen.cpp830
-rw-r--r--test/OpenMP/nvptx_target_printf_codegen.c116
-rw-r--r--test/OpenMP/nvptx_target_teams_codegen.cpp222
-rw-r--r--test/OpenMP/nvptx_teams_reduction_codegen.cpp1143
-rw-r--r--test/OpenMP/openmp_check.cpp28
-rw-r--r--test/OpenMP/ordered_messages.cpp11
-rw-r--r--test/OpenMP/target_parallel_codegen.cpp802
-rw-r--r--test/OpenMP/target_parallel_codegen_registration.cpp437
-rw-r--r--test/OpenMP/target_parallel_codegen_registration_naming.cpp66
-rw-r--r--test/OpenMP/target_parallel_default_messages.cpp3
-rw-r--r--test/OpenMP/target_parallel_for_collapse_messages.cpp26
-rw-r--r--test/OpenMP/target_parallel_for_ordered_messages.cpp26
-rw-r--r--test/OpenMP/target_parallel_if_codegen.cpp413
-rw-r--r--test/OpenMP/target_parallel_num_threads_codegen.cpp344
-rw-r--r--test/OpenMP/target_teams_codegen.cpp802
-rw-r--r--test/OpenMP/target_teams_codegen_registration.cpp437
-rw-r--r--test/OpenMP/target_teams_codegen_registration_naming.cpp66
-rw-r--r--test/OpenMP/target_teams_num_teams_codegen.cpp344
-rw-r--r--test/OpenMP/target_teams_thread_limit_codegen.cpp357
-rw-r--r--test/OpenMP/threadprivate_codegen.cpp2
-rw-r--r--test/OpenMP/vla_crash.c22
-rw-r--r--test/PCH/cxx-dependent-sized-ext-vector.cpp18
-rw-r--r--test/PCH/cxx-traits.cpp1
-rw-r--r--test/PCH/cxx-traits.h1
-rw-r--r--test/PCH/emit-dependencies.c9
-rw-r--r--test/PCH/macro-undef.cpp6
-rw-r--r--test/PCH/ocl_types.h3
-rw-r--r--test/PCH/pragma-pack.c90
-rw-r--r--test/Parser/altivec-csk-bool.c4
-rw-r--r--test/Parser/altivec.c6
-rw-r--r--test/Parser/attr-external-source-symbol-cxx11.cpp5
-rw-r--r--test/Parser/attr-external-source-symbol.m84
-rw-r--r--test/Parser/backtrack-off-by-one.cpp9
-rw-r--r--test/Parser/cxx-altivec.cpp6
-rw-r--r--test/Parser/cxx-template-decl.cpp10
-rw-r--r--test/Parser/cxx0x-ambig.cpp2
-rw-r--r--test/Parser/cxx0x-attributes.cpp10
-rw-r--r--test/Parser/cxx11-stmt-attributes.cpp1
-rw-r--r--test/Parser/cxx1z-class-template-argument-deduction.cpp194
-rw-r--r--test/Parser/declspec-recovery.c8
-rw-r--r--test/Parser/declspec-supported.c10
-rw-r--r--test/Parser/eof.cpp2
-rw-r--r--test/Parser/objc-available.m5
-rw-r--r--test/Parser/objc-cxx-keyword-identifiers.mm62
-rw-r--r--test/Parser/opencl-atomics-cl20.cl2
-rw-r--r--test/Parser/pragma-fp.cpp64
-rw-r--r--test/Parser/vector-cast-define.cl10
-rw-r--r--test/Parser/vsx.c4
-rw-r--r--test/Preprocessor/aarch64-target-features.c4
-rw-r--r--test/Preprocessor/arm-acle-6.4.c15
-rw-r--r--test/Preprocessor/arm-acle-6.5.c3
-rw-r--r--test/Preprocessor/arm-target-features.c32
-rw-r--r--test/Preprocessor/init.c292
-rw-r--r--test/Preprocessor/predefined-arch-macros.c149
-rw-r--r--test/Preprocessor/x86_target_features.c4
-rw-r--r--test/Profile/Inputs/cxx-class.proftext11
-rw-r--r--test/Profile/c-generate.c3
-rw-r--r--test/Profile/c-ternary.c15
-rw-r--r--test/Profile/cxx-class.cpp36
-rw-r--r--test/Profile/cxx-structors.cpp39
-rw-r--r--test/Profile/cxx-virtual-destructor-calls.cpp9
-rw-r--r--test/Rewriter/lit.local.cfg2
-rw-r--r--test/Sema/address-unaligned.c16
-rw-r--r--test/Sema/address_spaces.c2
-rw-r--r--test/Sema/alias-redefinition.c3
-rw-r--r--test/Sema/alloc-align-attr.c19
-rw-r--r--test/Sema/altivec-init.c6
-rw-r--r--test/Sema/arm-interrupt-attr.c16
-rw-r--r--test/Sema/ast-print.c9
-rw-r--r--test/Sema/attr-deprecated.c23
-rw-r--r--test/Sema/attr-external-source-symbol.c19
-rw-r--r--test/Sema/attr-ifunc.c4
-rw-r--r--test/Sema/auto-type.c2
-rw-r--r--test/Sema/avr-interrupt-attr.c8
-rw-r--r--test/Sema/avr-signal-attr.c8
-rw-r--r--test/Sema/builtins-ppc.c4
-rw-r--r--test/Sema/builtins-x86.c14
-rw-r--r--test/Sema/callingconv-cast.c13
-rw-r--r--test/Sema/const-eval.c11
-rw-r--r--test/Sema/declspec-naked.c11
-rw-r--r--test/Sema/designated-initializers.c17
-rw-r--r--test/Sema/enable_if.c4
-rw-r--r--test/Sema/enum-attr.c130
-rw-r--r--test/Sema/expr-address-of.c3
-rw-r--r--test/Sema/knr-def-call.c14
-rw-r--r--test/Sema/ms-inline-asm.c2
-rw-r--r--test/Sema/nonnull.c7
-rw-r--r--test/Sema/pr30306.cpp15
-rw-r--r--test/Sema/transparent-union.c24
-rw-r--r--test/Sema/unaligned-qualifier.c4
-rw-r--r--test/Sema/vector-ops.c114
-rw-r--r--test/Sema/warn-strict-prototypes.c9
-rw-r--r--test/Sema/warn-unreachable.c47
-rw-r--r--test/Sema/xray-log-args-oob.c9
-rw-r--r--test/Sema/xray-log-args-oob.cpp9
-rw-r--r--test/SemaCXX/Inputs/std-coroutine.h37
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp27
-rw-r--r--test/SemaCXX/P30636.cpp20
-rw-r--r--test/SemaCXX/PR9572.cpp43
-rw-r--r--test/SemaCXX/alloc-align-attr.cpp40
-rw-r--r--test/SemaCXX/altivec.cpp2
-rw-r--r--test/SemaCXX/anonymous-struct.cpp3
-rw-r--r--test/SemaCXX/array-bounds.cpp18
-rw-r--r--test/SemaCXX/attr-deprecated.cpp12
-rw-r--r--test/SemaCXX/attr-flag-enum-reject.cpp4
-rw-r--r--test/SemaCXX/attr-noreturn.cpp6
-rw-r--r--test/SemaCXX/attr-require-constant-initialization.cpp44
-rw-r--r--test/SemaCXX/auto-cxx0x.cpp9
-rw-r--r--test/SemaCXX/calling-conv-compat.cpp44
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp31
-rw-r--r--test/SemaCXX/constant-expression-cxx1y.cpp5
-rw-r--r--test/SemaCXX/coreturn.cpp32
-rw-r--r--test/SemaCXX/coroutine-unhandled_exception-warning.cpp24
-rw-r--r--test/SemaCXX/coroutines.cpp422
-rw-r--r--test/SemaCXX/cxx-altivec.cpp2
-rw-r--r--test/SemaCXX/cxx0x-class.cpp8
-rw-r--r--test/SemaCXX/cxx0x-initializer-aggregates.cpp2
-rw-r--r--test/SemaCXX/cxx0x-initializer-constructor.cpp3
-rw-r--r--test/SemaCXX/cxx0x-initializer-references.cpp16
-rw-r--r--test/SemaCXX/cxx0x-initializer-scalars.cpp10
-rw-r--r--test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp2
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp29
-rw-r--r--test/SemaCXX/cxx1y-generic-lambdas.cpp2
-rw-r--r--test/SemaCXX/cxx1y-variable-templates_in_class.cpp6
-rw-r--r--test/SemaCXX/cxx1y-variable-templates_top_level.cpp6
-rw-r--r--test/SemaCXX/cxx1z-class-template-argument-deduction.cpp215
-rw-r--r--test/SemaCXX/cxx1z-constexpr-lambdas.cpp119
-rw-r--r--test/SemaCXX/default-assignment-operator.cpp87
-rw-r--r--test/SemaCXX/default-constructor-initializers.cpp81
-rw-r--r--test/SemaCXX/designated-initializers-base-class.cpp12
-rw-r--r--test/SemaCXX/dllimport.cpp106
-rw-r--r--test/SemaCXX/enable_if.cpp35
-rw-r--r--test/SemaCXX/enum-attr.cpp108
-rw-r--r--test/SemaCXX/enum-scoped.cpp2
-rw-r--r--test/SemaCXX/format-strings.cpp20
-rw-r--r--test/SemaCXX/friend3.cpp27
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp47
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp58
-rw-r--r--test/SemaCXX/implicit-member-functions.cpp3
-rw-r--r--test/SemaCXX/implicit-virtual-member-functions.cpp74
-rw-r--r--test/SemaCXX/libstdcxx_pair_swap_hack.cpp2
-rw-r--r--test/SemaCXX/make_integer_seq.cpp2
-rw-r--r--test/SemaCXX/nested-name-spec.cpp4
-rw-r--r--test/SemaCXX/new-delete.cpp71
-rw-r--r--test/SemaCXX/no-wchar.cpp8
-rw-r--r--test/SemaCXX/printf-cstr.cpp47
-rw-r--r--test/SemaCXX/pseudo-destructors.cpp23
-rw-r--r--test/SemaCXX/ptrtomember.cpp4
-rw-r--r--test/SemaCXX/suppress.cpp25
-rw-r--r--test/SemaCXX/template-multiple-attr-propagation.cpp29
-rw-r--r--test/SemaCXX/template-specialization.cpp (renamed from test/Sema/template-specialization.cpp)0
-rw-r--r--test/SemaCXX/type-convert-construct.cpp10
-rw-r--r--test/SemaCXX/type-traits.cpp130
-rw-r--r--test/SemaCXX/uninitialized.cpp2
-rw-r--r--test/SemaCXX/virtual-base-used.cpp189
-rw-r--r--test/SemaCXX/virtual-member-functions-key-function.cpp43
-rw-r--r--test/SemaCXX/warn-bitfield-enum-conversion.cpp59
-rw-r--r--test/SemaCXX/warn-bool-conversion.cpp67
-rw-r--r--test/SemaCXX/warn-inconsistent-missing-destructor-override33
-rw-r--r--test/SemaCXX/warn-shadow.cpp107
-rw-r--r--test/SemaCXX/warn-thread-safety-parsing.cpp30
-rw-r--r--test/SemaCXX/warn-unused-lambda-capture.cpp188
-rw-r--r--test/SemaCXX/warn-unused-value.cpp6
-rw-r--r--test/SemaCXX/zero-length-arrays.cpp11
-rw-r--r--test/SemaObjC/arc-peformselector.m12
-rw-r--r--test/SemaObjC/arc-repeated-weak.mm21
-rw-r--r--test/SemaObjC/arc-unavailable-for-weakref.m1
-rw-r--r--test/SemaObjC/arc.m32
-rw-r--r--test/SemaObjC/attr-deprecated.m12
-rw-r--r--test/SemaObjC/category-attribute.m23
-rw-r--r--test/SemaObjC/class-message-protocol-lookup.m27
-rw-r--r--test/SemaObjC/default-synthesize-3.m4
-rw-r--r--test/SemaObjC/objc-class-property.m9
-rw-r--r--test/SemaObjC/property-typecheck-1.m5
-rw-r--r--test/SemaObjC/special-dep-unavail-warning.m4
-rw-r--r--test/SemaObjC/unsafe-perform-selector.m127
-rw-r--r--test/SemaObjC/warn-deprecated-implementations.m11
-rw-r--r--test/SemaObjCXX/arc-bridged-cast.mm16
-rw-r--r--test/SemaObjCXX/arc-ptr-comparison.mm24
-rw-r--r--test/SemaObjCXX/arc-system-header.mm2
-rw-r--r--test/SemaObjCXX/arc-templates.mm4
-rw-r--r--test/SemaObjCXX/arc-unavailable-for-weakref.mm1
-rw-r--r--test/SemaObjCXX/blocks.mm13
-rw-r--r--test/SemaObjCXX/ivar-construct.mm2
-rw-r--r--test/SemaObjCXX/objc-weak-type-traits.mm210
-rw-r--r--test/SemaObjCXX/objc-weak.mm28
-rw-r--r--test/SemaObjCXX/overload.mm27
-rw-r--r--test/SemaOpenCL/access-qualifier.cl4
-rw-r--r--test/SemaOpenCL/address-spaces-conversions-cl2.0.cl37
-rw-r--r--test/SemaOpenCL/as_type.cl9
-rw-r--r--test/SemaOpenCL/atomic-init.cl12
-rw-r--r--test/SemaOpenCL/builtins-amdgcn-error-f16.cl6
-rw-r--r--test/SemaOpenCL/builtins-amdgcn-error-gfx9.cl9
-rw-r--r--test/SemaOpenCL/builtins-amdgcn-error.cl50
-rw-r--r--test/SemaOpenCL/cl20-device-side-enqueue.cl21
-rw-r--r--test/SemaOpenCL/invalid-assignment-constant-address-space.cl (renamed from test/Sema/invalid-assignment-constant-address-space.c)3
-rw-r--r--test/SemaOpenCL/invalid-block.cl47
-rw-r--r--test/SemaOpenCL/invalid-logical-ops-1.1.cl57
-rw-r--r--test/SemaOpenCL/logical-ops.cl (renamed from test/SemaOpenCL/invalid-logical-ops-1.2.cl)59
-rw-r--r--test/SemaOpenCL/sampler_t.cl5
-rw-r--r--test/SemaOpenCL/types.cl6
-rw-r--r--test/SemaOpenCL/vector_swizzle_length.cl10
-rw-r--r--test/SemaTemplate/alias-templates.cpp11
-rw-r--r--test/SemaTemplate/deduction.cpp58
-rw-r--r--test/SemaTemplate/default-expr-arguments-3.cpp2
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp4
-rw-r--r--test/SemaTemplate/injected-class-name.cpp5
-rw-r--r--test/SemaTemplate/instantiate-c99.cpp19
-rw-r--r--test/SemaTemplate/instantiate-enum.cpp5
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp4
-rw-r--r--test/SemaTemplate/member-access-ambig.cpp2
-rw-r--r--test/SemaTemplate/ms-sizeof-missing-typename.cpp2
-rw-r--r--test/SemaTemplate/temp_arg.cpp2
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp8
-rw-r--r--test/SemaTemplate/temp_arg_template.cpp41
-rw-r--r--test/SemaTemplate/temp_arg_template_cxx1z.cpp33
-rw-r--r--test/SemaTemplate/temp_explicit.cpp25
-rw-r--r--test/SemaTemplate/template-id-expr.cpp13
-rw-r--r--test/SemaTemplate/typename-specifier-3.cpp3
-rw-r--r--test/SemaTemplate/typename-specifier.cpp2
-rw-r--r--test/SemaTemplate/undefined-template.cpp8
-rw-r--r--test/SemaTemplate/value-dependent-null-pointer-constant.cpp15
-rw-r--r--test/SemaTemplate/virtual-member-functions.cpp54
-rw-r--r--test/Tooling/lit.local.cfg2
-rw-r--r--test/lit.cfg27
-rw-r--r--test/lit.site.cfg.in11
-rw-r--r--tools/c-index-test/CMakeLists.txt3
-rw-r--r--tools/c-index-test/c-index-test.c16
-rw-r--r--tools/c-index-test/core_main.cpp85
-rw-r--r--tools/clang-check/ClangCheck.cpp1
-rw-r--r--tools/clang-format-vs/.gitignore1
-rw-r--r--tools/clang-format-vs/CMakeLists.txt7
-rw-r--r--tools/clang-format-vs/ClangFormat.sln4
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormat.csproj56
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs192
-rw-r--r--tools/clang-format-vs/ClangFormat/RunningDocTableEventsDispatcher.cs79
-rw-r--r--tools/clang-format-vs/ClangFormat/Vsix.cs96
-rw-r--r--tools/clang-format-vs/ClangFormat/license.txt39
-rw-r--r--tools/clang-format-vs/ClangFormat/packages.config1
-rw-r--r--tools/clang-format-vs/source.extension.vsixmanifest.in49
-rw-r--r--tools/clang-format/ClangFormat.cpp38
-rw-r--r--tools/clang-format/clang-format-test.el126
-rw-r--r--tools/clang-format/clang-format.el25
-rw-r--r--tools/clang-import-test/clang-import-test.cpp64
-rw-r--r--tools/clang-offload-bundler/ClangOffloadBundler.cpp7
-rw-r--r--tools/driver/CMakeLists.txt2
-rw-r--r--tools/driver/cc1as_main.cpp10
-rw-r--r--tools/driver/driver.cpp5
-rw-r--r--tools/libclang/CIndex.cpp18
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp9
-rw-r--r--tools/libclang/CXCursor.cpp1
-rw-r--r--tools/libclang/CXIndexDataConsumer.cpp1
-rw-r--r--tools/libclang/CXType.cpp14
-rw-r--r--tools/libclang/libclang.exports1
-rw-r--r--tools/scan-build-py/bin/analyze-build4
-rw-r--r--tools/scan-build-py/bin/analyze-build.bat1
-rw-r--r--tools/scan-build-py/bin/analyze-c++4
-rw-r--r--tools/scan-build-py/bin/analyze-c++.bat1
-rw-r--r--tools/scan-build-py/bin/analyze-cc4
-rw-r--r--tools/scan-build-py/bin/analyze-cc.bat1
-rw-r--r--tools/scan-build-py/bin/intercept-build4
-rw-r--r--tools/scan-build-py/bin/intercept-build.bat1
-rw-r--r--tools/scan-build-py/bin/intercept-c++4
-rw-r--r--tools/scan-build-py/bin/intercept-c++.bat1
-rw-r--r--tools/scan-build-py/bin/intercept-cc4
-rw-r--r--tools/scan-build-py/bin/intercept-cc.bat1
-rw-r--r--tools/scan-build-py/bin/scan-build4
-rw-r--r--tools/scan-build-py/bin/scan-build.bat1
-rw-r--r--tools/scan-build-py/libear/__init__.py4
-rw-r--r--tools/scan-build-py/libscanbuild/__init__.py185
-rw-r--r--tools/scan-build-py/libscanbuild/analyze.py766
-rw-r--r--tools/scan-build-py/libscanbuild/arguments.py431
-rw-r--r--tools/scan-build-py/libscanbuild/clang.py17
-rw-r--r--tools/scan-build-py/libscanbuild/intercept.py212
-rw-r--r--tools/scan-build-py/libscanbuild/report.py85
-rw-r--r--tools/scan-build-py/libscanbuild/runner.py302
-rw-r--r--tools/scan-build-py/tests/unit/__init__.py2
-rw-r--r--tools/scan-build-py/tests/unit/test_analyze.py328
-rw-r--r--tools/scan-build-py/tests/unit/test_intercept.py12
-rw-r--r--tools/scan-build-py/tests/unit/test_report.py15
-rw-r--r--tools/scan-build-py/tests/unit/test_runner.py322
-rw-r--r--tools/scan-build/CMakeLists.txt3
-rw-r--r--tools/scan-view/share/Reporter.py3
-rw-r--r--tools/scan-view/share/startfile.py3
-rw-r--r--unittests/ASTMatchers/ASTMatchersNodeTest.cpp59
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h35
-rw-r--r--unittests/Analysis/CFGTest.cpp14
-rw-r--r--unittests/Analysis/CMakeLists.txt5
-rw-r--r--unittests/Analysis/CloneDetectionTest.cpp110
-rw-r--r--unittests/Basic/CMakeLists.txt1
-rw-r--r--unittests/Basic/FileManagerTest.cpp52
-rw-r--r--unittests/Basic/MemoryBufferCacheTest.cpp94
-rw-r--r--unittests/Basic/SourceManagerTest.cpp10
-rw-r--r--unittests/Basic/VirtualFileSystemTest.cpp102
-rw-r--r--unittests/Driver/CMakeLists.txt1
-rw-r--r--unittests/Format/CMakeLists.txt4
-rw-r--r--unittests/Format/FormatTest.cpp1805
-rw-r--r--unittests/Format/FormatTestComments.cpp2373
-rw-r--r--unittests/Format/FormatTestJS.cpp208
-rw-r--r--unittests/Format/FormatTestJava.cpp19
-rw-r--r--unittests/Format/FormatTestObjC.cpp16
-rw-r--r--unittests/Format/FormatTestProto.cpp10
-rw-r--r--unittests/Format/FormatTestSelective.cpp10
-rw-r--r--unittests/Format/NamespaceEndCommentsFixerTest.cpp602
-rw-r--r--unittests/Lex/LexerTest.cpp5
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp7
-rw-r--r--unittests/Lex/PPConditionalDirectiveRecordTest.cpp4
-rw-r--r--unittests/Tooling/CMakeLists.txt3
-rw-r--r--unittests/Tooling/RefactoringTest.cpp210
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp86
-rw-r--r--utils/TableGen/ClangOptionDocEmitter.cpp391
-rw-r--r--utils/TableGen/TableGen.cpp10
-rw-r--r--utils/TableGen/TableGenBackends.h1
-rw-r--r--www/analyzer/alpha_checks.html24
-rw-r--r--www/cxx_dr_status.html24
-rw-r--r--www/cxx_status.html27
1805 files changed, 97960 insertions, 43699 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ff1ff210b56d..ca696b1ce79f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,6 +82,7 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
endif()
+ option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." ON)
option(LLVM_INSTALL_TOOLCHAIN_ONLY
"Only include toolchain files in the 'install' target." OFF)
@@ -185,6 +186,8 @@ if (LIBXML2_FOUND)
set(CLANG_HAVE_LIBXML 1)
endif()
+find_package(Z3 4.5)
+
include(CheckIncludeFile)
check_include_file(sys/resource.h CLANG_HAVE_RLIMITS)
@@ -329,10 +332,6 @@ if (APPLE)
endif()
endif()
-configure_file(
- ${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
- ${CLANG_BINARY_DIR}/include/clang/Config/config.h)
-
include(CMakeParseArguments)
include(AddClang)
@@ -368,21 +367,21 @@ option(CLANG_BUILD_TOOLS
"Build the Clang tools. If OFF, just generate build targets." ON)
option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
-if (CLANG_ENABLE_ARCMT)
- set(ENABLE_CLANG_ARCMT "1")
-else()
- set(ENABLE_CLANG_ARCMT "0")
-endif()
-
option(CLANG_ENABLE_STATIC_ANALYZER "Build static analyzer." ON)
-if (CLANG_ENABLE_STATIC_ANALYZER)
- set(ENABLE_CLANG_STATIC_ANALYZER "1")
-else()
- set(ENABLE_CLANG_STATIC_ANALYZER "0")
+
+option(CLANG_ANALYZER_BUILD_Z3
+ "Build the static analyzer with the Z3 constraint manager." OFF)
+
+if(NOT CLANG_ENABLE_STATIC_ANALYZER AND (CLANG_ENABLE_ARCMT OR CLANG_ANALYZER_BUILD_Z3))
+ message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT or Z3")
endif()
-if (NOT CLANG_ENABLE_STATIC_ANALYZER AND CLANG_ENABLE_ARCMT)
- message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT")
+if(CLANG_ANALYZER_BUILD_Z3)
+ if(Z3_FOUND)
+ set(CLANG_ANALYZER_WITH_Z3 1)
+ else()
+ message(FATAL_ERROR "Cannot find Z3 header file or shared library")
+ endif()
endif()
if(CLANG_ENABLE_ARCMT)
@@ -419,11 +418,6 @@ add_subdirectory(tools)
add_subdirectory(runtime)
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
-if (CLANG_BUILD_EXAMPLES)
- set(ENABLE_CLANG_EXAMPLES "1")
-else()
- set(ENABLE_CLANG_EXAMPLES "0")
-endif()
add_subdirectory(examples)
if(APPLE)
@@ -519,6 +513,10 @@ if (CLANG_ENABLE_BOOTSTRAP)
set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-stamps/)
set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-bins/)
+ if(BOOTSTRAP_LLVM_ENABLE_LLD)
+ add_dependencies(clang-bootstrap-deps lld)
+ endif()
+
# If the next stage is LTO we need to depend on LTO and possibly lld or LLVMgold
if(BOOTSTRAP_LLVM_ENABLE_LTO OR LLVM_ENABLE_LTO AND NOT LLVM_BUILD_INSTRUMENTED)
if(APPLE)
@@ -535,9 +533,7 @@ if (CLANG_ENABLE_BOOTSTRAP)
-DDYLD_LIBRARY_PATH=${LLVM_LIBRARY_OUTPUT_INTDIR})
elseif(NOT WIN32)
add_dependencies(clang-bootstrap-deps llvm-ar llvm-ranlib)
- if(BOOTSTRAP_LLVM_ENABLE_LLD)
- add_dependencies(clang-bootstrap-deps lld)
- elseif(LLVM_BINUTILS_INCDIR)
+ if(NOT BOOTSTRAP_LLVM_ENABLE_LLD AND LLVM_BINUTILS_INCDIR)
add_dependencies(clang-bootstrap-deps LLVMgold)
endif()
set(LTO_AR -DCMAKE_AR=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ar)
@@ -700,3 +696,7 @@ endif()
if (LLVM_ADD_NATIVE_VISUALIZERS_TO_SOLUTION)
add_subdirectory(utils/ClangVisualizers)
endif()
+
+configure_file(
+ ${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
+ ${CLANG_BINARY_DIR}/include/clang/Config/config.h)
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index cf867bbf7d0b..48fc8b13a209 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -1887,6 +1887,7 @@ TypeKind.OBJCID = TypeKind(27)
TypeKind.OBJCCLASS = TypeKind(28)
TypeKind.OBJCSEL = TypeKind(29)
TypeKind.FLOAT128 = TypeKind(30)
+TypeKind.HALF = TypeKind(31)
TypeKind.COMPLEX = TypeKind(100)
TypeKind.POINTER = TypeKind(101)
TypeKind.BLOCKPOINTER = TypeKind(102)
diff --git a/cmake/caches/Apple-stage2-ThinLTO.cmake b/cmake/caches/Apple-stage2-ThinLTO.cmake
new file mode 100644
index 000000000000..54e54e306e7a
--- /dev/null
+++ b/cmake/caches/Apple-stage2-ThinLTO.cmake
@@ -0,0 +1,6 @@
+# This file sets up a CMakeCache for Apple-style stage2 ThinLTO bootstrap. It is
+# specified by the stage1 build.
+
+
+set(LLVM_ENABLE_LTO THIN CACHE BOOL "")
+include(${CMAKE_CURRENT_LIST_DIR}/Apple-stage2.cmake)
diff --git a/cmake/caches/Fuchsia-stage2.cmake b/cmake/caches/Fuchsia-stage2.cmake
new file mode 100644
index 000000000000..2e1e9a155e14
--- /dev/null
+++ b/cmake/caches/Fuchsia-stage2.cmake
@@ -0,0 +1,66 @@
+# This file sets up a CMakeCache for the second stage of a Fuchsia toolchain
+# build.
+
+set(LLVM_TARGETS_TO_BUILD X86;AArch64 CACHE STRING "")
+
+set(PACKAGE_VENDOR Fuchsia CACHE STRING "")
+
+set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
+set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
+set(LLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD OFF CACHE BOOL "")
+set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
+set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
+set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
+set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
+
+set(LLVM_ENABLE_LTO ON CACHE BOOL "")
+if(NOT APPLE)
+ set(LLVM_ENABLE_LLD ON CACHE BOOL "")
+ set(CLANG_DEFAULT_LINKER lld CACHE STRING "")
+endif()
+
+if(APPLE)
+ set(LLDB_CODESIGN_IDENTITY "" CACHE STRING "")
+endif()
+
+set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
+
+set(LLVM_BUILTIN_TARGETS "x86_64-fuchsia-none;aarch64-fuchsia-none" CACHE STRING "")
+set(BUILTINS_x86_64-fuchsia-none_CMAKE_SYSROOT ${FUCHSIA_SYSROOT} CACHE STRING "")
+set(BUILTINS_x86_64-fuchsia-none_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
+set(BUILTINS_aarch64-fuchsia-none_CMAKE_SYSROOT ${FUCHSIA_SYSROOT} CACHE STRING "")
+set(BUILTINS_aarch64-fuchsia-none_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
+
+# Setup toolchain.
+set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
+set(LLVM_TOOLCHAIN_TOOLS
+ llvm-ar
+ llvm-cov
+ llvm-cxxfilt
+ llvm-dwarfdump
+ llvm-dsymutil
+ llvm-lib
+ llvm-nm
+ llvm-objdump
+ llvm-profdata
+ llvm-ranlib
+ llvm-readobj
+ llvm-size
+ llvm-symbolizer
+ CACHE STRING "")
+
+set(LLVM_DISTRIBUTION_COMPONENTS
+ clang
+ lld
+ lldb
+ liblldb
+ LTO
+ clang-format
+ clang-headers
+ builtins-x86_64-fuchsia-none
+ builtins-aarch64-fuchsia-none
+ runtimes
+ ${LLVM_TOOLCHAIN_TOOLS}
+ CACHE STRING "")
diff --git a/cmake/caches/Fuchsia.cmake b/cmake/caches/Fuchsia.cmake
new file mode 100644
index 000000000000..c8a8cf6d58b7
--- /dev/null
+++ b/cmake/caches/Fuchsia.cmake
@@ -0,0 +1,50 @@
+# This file sets up a CMakeCache for a Fuchsia toolchain build.
+
+set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "")
+
+set(PACKAGE_VENDOR Fuchsia CACHE STRING "")
+
+set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
+set(LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
+set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
+set(CLANG_INCLUDE_TESTS OFF CACHE BOOL "")
+set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "")
+set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
+set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
+
+set(CMAKE_BUILD_TYPE Release CACHE STRING "")
+
+set(BOOTSTRAP_LLVM_ENABLE_LTO ON CACHE BOOL "")
+if(NOT APPLE)
+ set(BOOTSTRAP_LLVM_ENABLE_LLD ON CACHE BOOL "")
+endif()
+
+if(APPLE)
+ set(COMPILER_RT_ENABLE_IOS OFF CACHE BOOL "")
+ set(COMPILER_RT_ENABLE_TVOS OFF CACHE BOOL "")
+ set(COMPILER_RT_ENABLE_WATCHOS OFF CACHE BOOL "")
+endif()
+
+set(CLANG_BOOTSTRAP_TARGETS
+ check-all
+ check-llvm
+ check-clang
+ llvm-config
+ test-suite
+ test-depends
+ llvm-test-depends
+ clang-test-depends
+ distribution
+ install-distribution
+ clang CACHE STRING "")
+
+if(FUCHSIA_SYSROOT)
+ set(EXTRA_ARGS -DFUCHSIA_SYSROOT=${FUCHSIA_SYSROOT})
+endif()
+
+# Setup the bootstrap build.
+set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
+set(CLANG_BOOTSTRAP_CMAKE_ARGS
+ ${EXTRA_ARGS}
+ -C ${CMAKE_CURRENT_LIST_DIR}/Fuchsia-stage2.cmake
+ CACHE STRING "")
diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt
index b784c0d215ea..be6d1d7257bc 100644
--- a/cmake/modules/CMakeLists.txt
+++ b/cmake/modules/CMakeLists.txt
@@ -4,17 +4,27 @@
set(CLANG_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/clang)
set(clang_cmake_builddir "${CMAKE_BINARY_DIR}/${CLANG_INSTALL_PACKAGE_DIR}")
+# Keep this in sync with llvm/cmake/CMakeLists.txt!
+set(LLVM_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm)
+set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}")
+
get_property(CLANG_EXPORTS GLOBAL PROPERTY CLANG_EXPORTS)
export(TARGETS ${CLANG_EXPORTS} FILE ${clang_cmake_builddir}/ClangTargets.cmake)
# Generate ClangConfig.cmake for the build tree.
set(CLANG_CONFIG_CMAKE_DIR "${clang_cmake_builddir}")
+set(CLANG_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}")
set(CLANG_CONFIG_EXPORTS_FILE "${clang_cmake_builddir}/ClangTargets.cmake")
+set(CLANG_CONFIG_INCLUDE_DIRS
+ "${CLANG_SOURCE_DIR}/include"
+ "${CLANG_BINARY_DIR}/include"
+ )
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/ClangConfig.cmake.in
${clang_cmake_builddir}/ClangConfig.cmake
@ONLY)
set(CLANG_CONFIG_CMAKE_DIR)
+set(CLANG_CONFIG_LLVM_CMAKE_DIR)
set(CLANG_CONFIG_EXPORTS_FILE)
# Generate ClangConfig.cmake for the install tree.
@@ -29,7 +39,11 @@ foreach(p ${_count})
get_filename_component(CLANG_INSTALL_PREFIX \"\${CLANG_INSTALL_PREFIX}\" PATH)")
endforeach(p)
set(CLANG_CONFIG_CMAKE_DIR "\${CLANG_INSTALL_PREFIX}/${CLANG_INSTALL_PACKAGE_DIR}")
+set(CLANG_CONFIG_LLVM_CMAKE_DIR "\${CLANG_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}")
set(CLANG_CONFIG_EXPORTS_FILE "\${CLANG_CMAKE_DIR}/ClangTargets.cmake")
+set(CLANG_CONFIG_INCLUDE_DIRS
+ "\${CLANG_INSTALL_PREFIX}/include"
+ )
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/ClangConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/ClangConfig.cmake
diff --git a/cmake/modules/ClangConfig.cmake.in b/cmake/modules/ClangConfig.cmake.in
index a946944dd991..03bca691c2b6 100644
--- a/cmake/modules/ClangConfig.cmake.in
+++ b/cmake/modules/ClangConfig.cmake.in
@@ -1,11 +1,13 @@
# This file allows users to call find_package(Clang) and pick up our targets.
-find_package(LLVM REQUIRED CONFIG)
-
@CLANG_CONFIG_CODE@
+find_package(LLVM REQUIRED CONFIG
+ HINTS "@CLANG_CONFIG_LLVM_CMAKE_DIR@")
+
set(CLANG_EXPORTED_TARGETS "@CLANG_EXPORTS@")
set(CLANG_CMAKE_DIR "@CLANG_CONFIG_CMAKE_DIR@")
+set(CLANG_INCLUDE_DIRS "@CLANG_CONFIG_INCLUDE_DIRS@")
# Provide all our library targets to users.
include("@CLANG_CONFIG_EXPORTS_FILE@")
diff --git a/cmake/modules/FindZ3.cmake b/cmake/modules/FindZ3.cmake
new file mode 100644
index 000000000000..779ef928da1b
--- /dev/null
+++ b/cmake/modules/FindZ3.cmake
@@ -0,0 +1,28 @@
+find_path(Z3_INCLUDE_DIR NAMES z3.h
+ PATH_SUFFIXES libz3 z3
+ )
+
+find_library(Z3_LIBRARIES NAMES z3 libz3
+ )
+
+find_program(Z3_EXECUTABLE z3)
+
+if(Z3_INCLUDE_DIR AND Z3_EXECUTABLE)
+ execute_process (COMMAND ${Z3_EXECUTABLE} -version
+ OUTPUT_VARIABLE libz3_version_str
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ string(REGEX REPLACE "^Z3 version ([0-9.]+)" "\\1"
+ Z3_VERSION_STRING "${libz3_version_str}")
+ unset(libz3_version_str)
+endif()
+
+# handle the QUIETLY and REQUIRED arguments and set Z3_FOUND to TRUE if
+# all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Z3
+ REQUIRED_VARS Z3_LIBRARIES Z3_INCLUDE_DIR
+ VERSION_VAR Z3_VERSION_STRING)
+
+mark_as_advanced(Z3_INCLUDE_DIR Z3_LIBRARIES)
diff --git a/docs/AttributeReference.rst b/docs/AttributeReference.rst
index db4812afdaa0..a763ddeaeb10 100644
--- a/docs/AttributeReference.rst
+++ b/docs/AttributeReference.rst
@@ -1,3119 +1,13 @@
..
-------------------------------------------------------------------
NOTE: This file is automatically generated by running clang-tblgen
- -gen-attr-docs. Do not edit this file by hand!!
+ -gen-attr-docs. Do not edit this file by hand!! The contents for
+ this file are automatically generated by a server-side process.
+
+ Please do not commit this file. The file exists for local testing
+ purposes only.
-------------------------------------------------------------------
===================
Attributes in Clang
-===================
-.. contents::
- :local:
-
-Introduction
-============
-
-This page lists the attributes currently supported by Clang.
-
-Function Attributes
-===================
-
-
-interrupt
----------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on
-ARM targets. This attribute may be attached to a function definition and
-instructs the backend to generate appropriate function entry/exit code so that
-it can be used directly as an interrupt service routine.
-
-The parameter passed to the interrupt attribute is optional, but if
-provided it must be a string literal with one of the following values: "IRQ",
-"FIQ", "SWI", "ABORT", "UNDEF".
-
-The semantics are as follows:
-
-- If the function is AAPCS, Clang instructs the backend to realign the stack to
- 8 bytes on entry. This is a general requirement of the AAPCS at public
- interfaces, but may not hold when an exception is taken. Doing this allows
- other AAPCS functions to be called.
-- If the CPU is M-class this is all that needs to be done since the architecture
- itself is designed in such a way that functions obeying the normal AAPCS ABI
- constraints are valid exception handlers.
-- If the CPU is not M-class, the prologue and epilogue are modified to save all
- non-banked registers that are used, so that upon return the user-mode state
- will not be corrupted. Note that to avoid unnecessary overhead, only
- general-purpose (integer) registers are saved in this way. If VFP operations
- are needed, that state must be saved manually.
-
- Specifically, interrupt kinds other than "FIQ" will save all core registers
- except "lr" and "sp". "FIQ" interrupts will save r0-r7.
-- If the CPU is not M-class, the return instruction is changed to one of the
- canonical sequences permitted by the architecture for exception return. Where
- possible the function itself will make the necessary "lr" adjustments so that
- the "preferred return address" is selected.
-
- Unfortunately the compiler is unable to make this guarantee for an "UNDEF"
- handler, where the offset from "lr" to the preferred return address depends on
- the execution state of the code which generated the exception. In this case
- a sequence equivalent to "movs pc, lr" will be used.
-
-
-abi_tag (gnu::abi_tag)
-----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``abi_tag`` attribute can be applied to a function, variable, class or
-inline namespace declaration to modify the mangled name of the entity. It gives
-the ability to distinguish between different versions of the same entity but
-with different ABI versions supported. For example, a newer version of a class
-could have a different set of data members and thus have a different size. Using
-the ``abi_tag`` attribute, it is possible to have different mangled names for
-a global variable of the class type. Therefor, the old code could keep using
-the old manged name and the new code will use the new mangled name with tags.
-
-
-acquire_capability (acquire_shared_capability, clang::acquire_capability, clang::acquire_shared_capability)
------------------------------------------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Marks a function as acquiring a capability.
-
-
-alloc_size (gnu::alloc_size)
-----------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``alloc_size`` attribute can be placed on functions that return pointers in
-order to hint to the compiler how many bytes of memory will be available at the
-returned poiner. ``alloc_size`` takes one or two arguments.
-
-- ``alloc_size(N)`` implies that argument number N equals the number of
- available bytes at the returned pointer.
-- ``alloc_size(N, M)`` implies that the product of argument number N and
- argument number M equals the number of available bytes at the returned
- pointer.
-
-Argument numbers are 1-based.
-
-An example of how to use ``alloc_size``
-
-.. code-block:: c
-
- void *my_malloc(int a) __attribute__((alloc_size(1)));
- void *my_calloc(int a, int b) __attribute__((alloc_size(1, 2)));
-
- int main() {
- void *const p = my_malloc(100);
- assert(__builtin_object_size(p, 0) == 100);
- void *const a = my_calloc(20, 5);
- assert(__builtin_object_size(a, 0) == 100);
- }
-
-.. Note:: This attribute works differently in clang than it does in GCC.
- Specifically, clang will only trace ``const`` pointers (as above); we give up
- on pointers that are not marked as ``const``. In the vast majority of cases,
- this is unimportant, because LLVM has support for the ``alloc_size``
- attribute. However, this may cause mildly unintuitive behavior when used with
- other attributes, such as ``enable_if``.
-
-
-interrupt
----------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Clang supports the GNU style ``__attribute__((interrupt))`` attribute on
-x86/x86-64 targets.The compiler generates function entry and exit sequences
-suitable for use in an interrupt handler when this attribute is present.
-The 'IRET' instruction, instead of the 'RET' instruction, is used to return
-from interrupt or exception handlers. All registers, except for the EFLAGS
-register which is restored by the 'IRET' instruction, are preserved by the
-compiler.
-
-Any interruptible-without-stack-switch code must be compiled with
--mno-red-zone since interrupt handlers can and will, because of the
-hardware design, touch the red zone.
-
-1. interrupt handler must be declared with a mandatory pointer argument:
-
- .. code-block:: c
-
- struct interrupt_frame
- {
- uword_t ip;
- uword_t cs;
- uword_t flags;
- uword_t sp;
- uword_t ss;
- };
-
- __attribute__ ((interrupt))
- void f (struct interrupt_frame *frame) {
- ...
- }
-
-2. exception handler:
-
- The exception handler is very similar to the interrupt handler with
- a different mandatory function signature:
-
- .. code-block:: c
-
- __attribute__ ((interrupt))
- void f (struct interrupt_frame *frame, uword_t error_code) {
- ...
- }
-
- and compiler pops 'ERROR_CODE' off stack before the 'IRET' instruction.
-
- The exception handler should only be used for exceptions which push an
- error code and all other exceptions must use the interrupt handler.
- The system will crash if the wrong handler is used.
-
-
-assert_capability (assert_shared_capability, clang::assert_capability, clang::assert_shared_capability)
--------------------------------------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Marks a function that dynamically tests whether a capability is held, and halts
-the program if it is not held.
-
-
-assume_aligned (gnu::assume_aligned)
-------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Use ``__attribute__((assume_aligned(<alignment>[,<offset>]))`` on a function
-declaration to specify that the return value of the function (which must be a
-pointer type) has the specified offset, in bytes, from an address with the
-specified alignment. The offset is taken to be zero if omitted.
-
-.. code-block:: c++
-
- // The returned pointer value has 32-byte alignment.
- void *a() __attribute__((assume_aligned (32)));
-
- // The returned pointer value is 4 bytes greater than an address having
- // 32-byte alignment.
- void *b() __attribute__((assume_aligned (32, 4)));
-
-Note that this attribute provides information to the compiler regarding a
-condition that the code already ensures is true. It does not cause the compiler
-to enforce the provided alignment assumption.
-
-
-availability
-------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-The ``availability`` attribute can be placed on declarations to describe the
-lifecycle of that declaration relative to operating system versions. Consider
-the function declaration for a hypothetical function ``f``:
-
-.. code-block:: c++
-
- void f(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
-
-The availability attribute states that ``f`` was introduced in Mac OS X 10.4,
-deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information
-is used by Clang to determine when it is safe to use ``f``: for example, if
-Clang is instructed to compile code for Mac OS X 10.5, a call to ``f()``
-succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call
-succeeds but Clang emits a warning specifying that the function is deprecated.
-Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call
-fails because ``f()`` is no longer available.
-
-The availability attribute is a comma-separated list starting with the
-platform name and then including clauses specifying important milestones in the
-declaration's lifetime (in any order) along with additional information. Those
-clauses can be:
-
-introduced=\ *version*
- The first version in which this declaration was introduced.
-
-deprecated=\ *version*
- The first version in which this declaration was deprecated, meaning that
- users should migrate away from this API.
-
-obsoleted=\ *version*
- The first version in which this declaration was obsoleted, meaning that it
- was removed completely and can no longer be used.
-
-unavailable
- This declaration is never available on this platform.
-
-message=\ *string-literal*
- Additional message text that Clang will provide when emitting a warning or
- error about use of a deprecated or obsoleted declaration. Useful to direct
- users to replacement APIs.
-
-replacement=\ *string-literal*
- Additional message text that Clang will use to provide Fix-It when emitting
- a warning about use of a deprecated declaration. The Fix-It will replace
- the deprecated declaration with the new declaration specified.
-
-Multiple availability attributes can be placed on a declaration, which may
-correspond to different platforms. Only the availability attribute with the
-platform corresponding to the target platform will be used; any others will be
-ignored. If no availability attribute specifies availability for the current
-target platform, the availability attributes are ignored. Supported platforms
-are:
-
-``ios``
- Apple's iOS operating system. The minimum deployment target is specified by
- the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*``
- command-line arguments.
-
-``macos``
- Apple's Mac OS X operating system. The minimum deployment target is
- specified by the ``-mmacosx-version-min=*version*`` command-line argument.
- ``macosx`` is supported for backward-compatibility reasons, but it is
- deprecated.
-
-``tvos``
- Apple's tvOS operating system. The minimum deployment target is specified by
- the ``-mtvos-version-min=*version*`` command-line argument.
-
-``watchos``
- Apple's watchOS operating system. The minimum deployment target is specified by
- the ``-mwatchos-version-min=*version*`` command-line argument.
-
-A declaration can typically be used even when deploying back to a platform
-version prior to when the declaration was introduced. When this happens, the
-declaration is `weakly linked
-<https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html>`_,
-as if the ``weak_import`` attribute were added to the declaration. A
-weakly-linked declaration may or may not be present a run-time, and a program
-can determine whether the declaration is present by checking whether the
-address of that declaration is non-NULL.
-
-The flag ``strict`` disallows using API when deploying back to a
-platform version prior to when the declaration was introduced. An
-attempt to use such API before its introduction causes a hard error.
-Weakly-linking is almost always a better API choice, since it allows
-users to query availability at runtime.
-
-If there are multiple declarations of the same entity, the availability
-attributes must either match on a per-platform basis or later
-declarations must not have availability attributes for that
-platform. For example:
-
-.. code-block:: c
-
- void g(void) __attribute__((availability(macos,introduced=10.4)));
- void g(void) __attribute__((availability(macos,introduced=10.4))); // okay, matches
- void g(void) __attribute__((availability(ios,introduced=4.0))); // okay, adds a new platform
- void g(void); // okay, inherits both macos and ios availability from above.
- void g(void) __attribute__((availability(macos,introduced=10.5))); // error: mismatch
-
-When one method overrides another, the overriding method can be more widely available than the overridden method, e.g.,:
-
-.. code-block:: objc
-
- @interface A
- - (id)method __attribute__((availability(macos,introduced=10.4)));
- - (id)method2 __attribute__((availability(macos,introduced=10.4)));
- @end
-
- @interface B : A
- - (id)method __attribute__((availability(macos,introduced=10.3))); // okay: method moved into base class later
- - (id)method __attribute__((availability(macos,introduced=10.5))); // error: this method was available via the base class in 10.4
- @end
-
-
-_Noreturn
----------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-A function declared as ``_Noreturn`` shall not return to its caller. The
-compiler will generate a diagnostic for a function declared as ``_Noreturn``
-that appears to be capable of returning to its caller.
-
-
-noreturn
---------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","X","","", ""
-
-A function declared as ``[[noreturn]]`` shall not return to its caller. The
-compiler will generate a diagnostic for a function declared as ``[[noreturn]]``
-that appears to be capable of returning to its caller.
-
-
-carries_dependency
-------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``carries_dependency`` attribute specifies dependency propagation into and
-out of functions.
-
-When specified on a function or Objective-C method, the ``carries_dependency``
-attribute means that the return value carries a dependency out of the function,
-so that the implementation need not constrain ordering upon return from that
-function. Implementations of the function and its caller may choose to preserve
-dependencies instead of emitting memory ordering instructions such as fences.
-
-Note, this attribute does not change the meaning of the program, but may result
-in generation of more efficient code.
-
-
-convergent (clang::convergent)
-------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``convergent`` attribute can be placed on a function declaration. It is
-translated into the LLVM ``convergent`` attribute, which indicates that the call
-instructions of a function with this attribute cannot be made control-dependent
-on any additional values.
-
-In languages designed for SPMD/SIMT programming model, e.g. OpenCL or CUDA,
-the call instructions of a function with this attribute must be executed by
-all work items or threads in a work group or sub group.
-
-This attribute is different from ``noduplicate`` because it allows duplicating
-function calls if it can be proved that the duplicated function calls are
-not made control-dependent on any additional values, e.g., unrolling a loop
-executed by all work items.
-
-Sample usage:
-.. code-block:: c
-
- void convfunc(void) __attribute__((convergent));
- // Setting it as a C++11 attribute is also valid in a C++ program.
- // void convfunc(void) [[clang::convergent]];
-
-
-deprecated (gnu::deprecated)
-----------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","X","", ""
-
-The ``deprecated`` attribute can be applied to a function, a variable, or a
-type. This is useful when identifying functions, variables, or types that are
-expected to be removed in a future version of a program.
-
-Consider the function declaration for a hypothetical function ``f``:
-
-.. code-block:: c++
-
- void f(void) __attribute__((deprecated("message", "replacement")));
-
-When spelled as `__attribute__((deprecated))`, the deprecated attribute can have
-two optional string arguments. The first one is the message to display when
-emitting the warning; the second one enables the compiler to provide a Fix-It
-to replace the deprecated name with a new name. Otherwise, when spelled as
-`[[gnu::deprecated]] or [[deprecated]]`, the attribute can have one optional
-string argument which is the message to display when emitting the warning.
-
-
-diagnose_if
------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-The ``diagnose_if`` attribute can be placed on function declarations to emit
-warnings or errors at compile-time if calls to the attributed function meet
-certain user-defined criteria. For example:
-
-.. code-block:: c
-
- void abs(int a)
- __attribute__((diagnose_if(a >= 0, "Redundant abs call", "warning")));
- void must_abs(int a)
- __attribute__((diagnose_if(a >= 0, "Redundant abs call", "error")));
-
- int val = abs(1); // warning: Redundant abs call
- int val2 = must_abs(1); // error: Redundant abs call
- int val3 = abs(val);
- int val4 = must_abs(val); // Because run-time checks are not emitted for
- // diagnose_if attributes, this executes without
- // issue.
-
-
-``diagnose_if`` is closely related to ``enable_if``, with a few key differences:
-
-* Overload resolution is not aware of ``diagnose_if`` attributes: they're
- considered only after we select the best candidate from a given candidate set.
-* Function declarations that differ only in their ``diagnose_if`` attributes are
- considered to be redeclarations of the same function (not overloads).
-* If the condition provided to ``diagnose_if`` cannot be evaluated, no
- diagnostic will be emitted.
-
-Otherwise, ``diagnose_if`` is essentially the logical negation of ``enable_if``.
-
-As a result of bullet number two, ``diagnose_if`` attributes will stack on the
-same function. For example:
-
-.. code-block:: c
-
- int foo() __attribute__((diagnose_if(1, "diag1", "warning")));
- int foo() __attribute__((diagnose_if(1, "diag2", "warning")));
-
- int bar = foo(); // warning: diag1
- // warning: diag2
- int (*fooptr)(void) = foo; // warning: diag1
- // warning: diag2
-
- constexpr int supportsAPILevel(int N) { return N < 5; }
- int baz(int a)
- __attribute__((diagnose_if(!supportsAPILevel(10),
- "Upgrade to API level 10 to use baz", "error")));
- int baz(int a)
- __attribute__((diagnose_if(!a, "0 is not recommended.", "warning")));
-
- int (*bazptr)(int) = baz; // error: Upgrade to API level 10 to use baz
- int v = baz(0); // error: Upgrade to API level 10 to use baz
-
-Query for this feature with ``__has_attribute(diagnose_if)``.
-
-
-disable_tail_calls (clang::disable_tail_calls)
-----------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``disable_tail_calls`` attribute instructs the backend to not perform tail call optimization inside the marked function.
-
-For example:
-
- .. code-block:: c
-
- int callee(int);
-
- int foo(int a) __attribute__((disable_tail_calls)) {
- return callee(a); // This call is not tail-call optimized.
- }
-
-Marking virtual functions as ``disable_tail_calls`` is legal.
-
- .. code-block:: c++
-
- int callee(int);
-
- class Base {
- public:
- [[clang::disable_tail_calls]] virtual int foo1() {
- return callee(); // This call is not tail-call optimized.
- }
- };
-
- class Derived1 : public Base {
- public:
- int foo1() override {
- return callee(); // This call is tail-call optimized.
- }
- };
-
-
-enable_if
----------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-.. Note:: Some features of this attribute are experimental. The meaning of
- multiple enable_if attributes on a single declaration is subject to change in
- a future version of clang. Also, the ABI is not standardized and the name
- mangling may change in future versions. To avoid that, use asm labels.
-
-The ``enable_if`` attribute can be placed on function declarations to control
-which overload is selected based on the values of the function's arguments.
-When combined with the ``overloadable`` attribute, this feature is also
-available in C.
-
-.. code-block:: c++
-
- int isdigit(int c);
- int isdigit(int c) __attribute__((enable_if(c <= -1 || c > 255, "chosen when 'c' is out of range"))) __attribute__((unavailable("'c' must have the value of an unsigned char or EOF")));
-
- void foo(char c) {
- isdigit(c);
- isdigit(10);
- isdigit(-10); // results in a compile-time error.
- }
-
-The enable_if attribute takes two arguments, the first is an expression written
-in terms of the function parameters, the second is a string explaining why this
-overload candidate could not be selected to be displayed in diagnostics. The
-expression is part of the function signature for the purposes of determining
-whether it is a redeclaration (following the rules used when determining
-whether a C++ template specialization is ODR-equivalent), but is not part of
-the type.
-
-The enable_if expression is evaluated as if it were the body of a
-bool-returning constexpr function declared with the arguments of the function
-it is being applied to, then called with the parameters at the call site. If the
-result is false or could not be determined through constant expression
-evaluation, then this overload will not be chosen and the provided string may
-be used in a diagnostic if the compile fails as a result.
-
-Because the enable_if expression is an unevaluated context, there are no global
-state changes, nor the ability to pass information from the enable_if
-expression to the function body. For example, suppose we want calls to
-strnlen(strbuf, maxlen) to resolve to strnlen_chk(strbuf, maxlen, size of
-strbuf) only if the size of strbuf can be determined:
-
-.. code-block:: c++
-
- __attribute__((always_inline))
- static inline size_t strnlen(const char *s, size_t maxlen)
- __attribute__((overloadable))
- __attribute__((enable_if(__builtin_object_size(s, 0) != -1))),
- "chosen when the buffer size is known but 'maxlen' is not")))
- {
- return strnlen_chk(s, maxlen, __builtin_object_size(s, 0));
- }
-
-Multiple enable_if attributes may be applied to a single declaration. In this
-case, the enable_if expressions are evaluated from left to right in the
-following manner. First, the candidates whose enable_if expressions evaluate to
-false or cannot be evaluated are discarded. If the remaining candidates do not
-share ODR-equivalent enable_if expressions, the overload resolution is
-ambiguous. Otherwise, enable_if overload resolution continues with the next
-enable_if attribute on the candidates that have not been discarded and have
-remaining enable_if attributes. In this way, we pick the most specific
-overload out of a number of viable overloads using enable_if.
-
-.. code-block:: c++
-
- void f() __attribute__((enable_if(true, ""))); // #1
- void f() __attribute__((enable_if(true, ""))) __attribute__((enable_if(true, ""))); // #2
-
- void g(int i, int j) __attribute__((enable_if(i, ""))); // #1
- void g(int i, int j) __attribute__((enable_if(j, ""))) __attribute__((enable_if(true))); // #2
-
-In this example, a call to f() is always resolved to #2, as the first enable_if
-expression is ODR-equivalent for both declarations, but #1 does not have another
-enable_if expression to continue evaluating, so the next round of evaluation has
-only a single candidate. In a call to g(1, 1), the call is ambiguous even though
-#2 has more enable_if attributes, because the first enable_if expressions are
-not ODR-equivalent.
-
-Query for this feature with ``__has_attribute(enable_if)``.
-
-Note that functions with one or more ``enable_if`` attributes may not have
-their address taken, unless all of the conditions specified by said
-``enable_if`` are constants that evaluate to ``true``. For example:
-
-.. code-block:: c
-
- const int TrueConstant = 1;
- const int FalseConstant = 0;
- int f(int a) __attribute__((enable_if(a > 0, "")));
- int g(int a) __attribute__((enable_if(a == 0 || a != 0, "")));
- int h(int a) __attribute__((enable_if(1, "")));
- int i(int a) __attribute__((enable_if(TrueConstant, "")));
- int j(int a) __attribute__((enable_if(FalseConstant, "")));
-
- void fn() {
- int (*ptr)(int);
- ptr = &f; // error: 'a > 0' is not always true
- ptr = &g; // error: 'a == 0 || a != 0' is not a truthy constant
- ptr = &h; // OK: 1 is a truthy constant
- ptr = &i; // OK: 'TrueConstant' is a truthy constant
- ptr = &j; // error: 'FalseConstant' is a constant, but not truthy
- }
-
-Because ``enable_if`` evaluation happens during overload resolution,
-``enable_if`` may give unintuitive results when used with templates, depending
-on when overloads are resolved. In the example below, clang will emit a
-diagnostic about no viable overloads for ``foo`` in ``bar``, but not in ``baz``:
-
-.. code-block:: c++
-
- double foo(int i) __attribute__((enable_if(i > 0, "")));
- void *foo(int i) __attribute__((enable_if(i <= 0, "")));
- template <int I>
- auto bar() { return foo(I); }
-
- template <typename T>
- auto baz() { return foo(T::number); }
-
- struct WithNumber { constexpr static int number = 1; };
- void callThem() {
- bar<sizeof(WithNumber)>();
- baz<WithNumber>();
- }
-
-This is because, in ``bar``, ``foo`` is resolved prior to template
-instantiation, so the value for ``I`` isn't known (thus, both ``enable_if``
-conditions for ``foo`` fail). However, in ``baz``, ``foo`` is resolved during
-template instantiation, so the value for ``T::number`` is known.
-
-
-flatten (gnu::flatten)
-----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``flatten`` attribute causes calls within the attributed function to
-be inlined unless it is impossible to do so, for example if the body of the
-callee is unavailable or if the callee has the ``noinline`` attribute.
-
-
-format (gnu::format)
---------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Clang supports the ``format`` attribute, which indicates that the function
-accepts a ``printf`` or ``scanf``-like format string and corresponding
-arguments or a ``va_list`` that contains these arguments.
-
-Please see `GCC documentation about format attribute
-<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ to find details
-about attribute syntax.
-
-Clang implements two kinds of checks with this attribute.
-
-#. Clang checks that the function with the ``format`` attribute is called with
- a format string that uses format specifiers that are allowed, and that
- arguments match the format string. This is the ``-Wformat`` warning, it is
- on by default.
-
-#. Clang checks that the format string argument is a literal string. This is
- the ``-Wformat-nonliteral`` warning, it is off by default.
-
- Clang implements this mostly the same way as GCC, but there is a difference
- for functions that accept a ``va_list`` argument (for example, ``vprintf``).
- GCC does not emit ``-Wformat-nonliteral`` warning for calls to such
- functions. Clang does not warn if the format string comes from a function
- parameter, where the function is annotated with a compatible attribute,
- otherwise it warns. For example:
-
- .. code-block:: c
-
- __attribute__((__format__ (__scanf__, 1, 3)))
- void foo(const char* s, char *buf, ...) {
- va_list ap;
- va_start(ap, buf);
-
- vprintf(s, ap); // warning: format string is not a string literal
- }
-
- In this case we warn because ``s`` contains a format string for a
- ``scanf``-like function, but it is passed to a ``printf``-like function.
-
- If the attribute is removed, clang still warns, because the format string is
- not a string literal.
-
- Another example:
-
- .. code-block:: c
-
- __attribute__((__format__ (__printf__, 1, 3)))
- void foo(const char* s, char *buf, ...) {
- va_list ap;
- va_start(ap, buf);
-
- vprintf(s, ap); // warning
- }
-
- In this case Clang does not warn because the format string ``s`` and
- the corresponding arguments are annotated. If the arguments are
- incorrect, the caller of ``foo`` will receive a warning.
-
-
-ifunc (gnu::ifunc)
-------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-``__attribute__((ifunc("resolver")))`` is used to mark that the address of a declaration should be resolved at runtime by calling a resolver function.
-
-The symbol name of the resolver function is given in quotes. A function with this name (after mangling) must be defined in the current translation unit; it may be ``static``. The resolver function should take no arguments and return a pointer.
-
-The ``ifunc`` attribute may only be used on a function declaration. A function declaration with an ``ifunc`` attribute is considered to be a definition of the declared entity. The entity must not have weak linkage; for example, in C++, it cannot be applied to a declaration if a definition at that location would be considered inline.
-
-Not all targets support this attribute. ELF targets support this attribute when using binutils v2.20.1 or higher and glibc v2.11.1 or higher. Non-ELF targets currently do not support this attribute.
-
-
-internal_linkage (clang::internal_linkage)
-------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``internal_linkage`` attribute changes the linkage type of the declaration to internal.
-This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition,
-this attribute affects all methods and static data members of that class.
-This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables.
-
-
-interrupt
----------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on
-MIPS targets. This attribute may be attached to a function definition and instructs
-the backend to generate appropriate function entry/exit code so that it can be used
-directly as an interrupt service routine.
-
-By default, the compiler will produce a function prologue and epilogue suitable for
-an interrupt service routine that handles an External Interrupt Controller (eic)
-generated interrupt. This behaviour can be explicitly requested with the "eic"
-argument.
-
-Otherwise, for use with vectored interrupt mode, the argument passed should be
-of the form "vector=LEVEL" where LEVEL is one of the following values:
-"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will
-then set the interrupt mask to the corresponding level which will mask all
-interrupts up to and including the argument.
-
-The semantics are as follows:
-
-- The prologue is modified so that the Exception Program Counter (EPC) and
- Status coprocessor registers are saved to the stack. The interrupt mask is
- set so that the function can only be interrupted by a higher priority
- interrupt. The epilogue will restore the previous values of EPC and Status.
-
-- The prologue and epilogue are modified to save and restore all non-kernel
- registers as necessary.
-
-- The FPU is disabled in the prologue, as the floating pointer registers are not
- spilled to the stack.
-
-- The function return sequence is changed to use an exception return instruction.
-
-- The parameter sets the interrupt mask for the function corresponding to the
- interrupt level specified. If no mask is specified the interrupt mask
- defaults to "eic".
-
-
-noalias
--------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","X","", ""
-
-The ``noalias`` attribute indicates that the only memory accesses inside
-function are loads and stores from objects pointed to by its pointer-typed
-arguments, with arbitrary offsets.
-
-
-noduplicate (clang::noduplicate)
---------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``noduplicate`` attribute can be placed on function declarations to control
-whether function calls to this function can be duplicated or not as a result of
-optimizations. This is required for the implementation of functions with
-certain special requirements, like the OpenCL "barrier" function, that might
-need to be run concurrently by all the threads that are executing in lockstep
-on the hardware. For example this attribute applied on the function
-"nodupfunc" in the code below avoids that:
-
-.. code-block:: c
-
- void nodupfunc() __attribute__((noduplicate));
- // Setting it as a C++11 attribute is also valid
- // void nodupfunc() [[clang::noduplicate]];
- void foo();
- void bar();
-
- nodupfunc();
- if (a > n) {
- foo();
- } else {
- bar();
- }
-
-gets possibly modified by some optimizations into code similar to this:
-
-.. code-block:: c
-
- if (a > n) {
- nodupfunc();
- foo();
- } else {
- nodupfunc();
- bar();
- }
-
-where the call to "nodupfunc" is duplicated and sunk into the two branches
-of the condition.
-
-
-no_sanitize (clang::no_sanitize)
---------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Use the ``no_sanitize`` attribute on a function declaration to specify
-that a particular instrumentation or set of instrumentations should not be
-applied to that function. The attribute takes a list of string literals,
-which have the same meaning as values accepted by the ``-fno-sanitize=``
-flag. For example, ``__attribute__((no_sanitize("address", "thread")))``
-specifies that AddressSanitizer and ThreadSanitizer should not be applied
-to the function.
-
-See :ref:`Controlling Code Generation <controlling-code-generation>` for a
-full list of supported sanitizer flags.
-
-
-no_sanitize_address (no_address_safety_analysis, gnu::no_address_safety_analysis, gnu::no_sanitize_address)
------------------------------------------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-.. _langext-address_sanitizer:
-
-Use ``__attribute__((no_sanitize_address))`` on a function declaration to
-specify that address safety instrumentation (e.g. AddressSanitizer) should
-not be applied to that function.
-
-
-no_sanitize_thread
-------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-.. _langext-thread_sanitizer:
-
-Use ``__attribute__((no_sanitize_thread))`` on a function declaration to
-specify that checks for data races on plain (non-atomic) memory accesses should
-not be inserted by ThreadSanitizer. The function is still instrumented by the
-tool to avoid false positives and provide meaningful stack traces.
-
-
-no_sanitize_memory
-------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-.. _langext-memory_sanitizer:
-
-Use ``__attribute__((no_sanitize_memory))`` on a function declaration to
-specify that checks for uninitialized memory should not be inserted
-(e.g. by MemorySanitizer). The function may still be instrumented by the tool
-to avoid false positives in other places.
-
-
-no_split_stack (gnu::no_split_stack)
-------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``no_split_stack`` attribute disables the emission of the split stack
-preamble for a particular function. It has no effect if ``-fsplit-stack``
-is not specified.
-
-
-not_tail_called (clang::not_tail_called)
-----------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``.
-
-For example, it prevents tail-call optimization in the following case:
-
- .. code-block:: c
-
- int __attribute__((not_tail_called)) foo1(int);
-
- int foo2(int a) {
- return foo1(a); // No tail-call optimization on direct calls.
- }
-
-However, it doesn't prevent tail-call optimization in this case:
-
- .. code-block:: c
-
- int __attribute__((not_tail_called)) foo1(int);
-
- int foo2(int a) {
- int (*fn)(int) = &foo1;
-
- // not_tail_called has no effect on an indirect call even if the call can be
- // resolved at compile time.
- return (*fn)(a);
- }
-
-Marking virtual functions as ``not_tail_called`` is an error:
-
- .. code-block:: c++
-
- class Base {
- public:
- // not_tail_called on a virtual function is an error.
- [[clang::not_tail_called]] virtual int foo1();
-
- virtual int foo2();
-
- // Non-virtual functions can be marked ``not_tail_called``.
- [[clang::not_tail_called]] int foo3();
- };
-
- class Derived1 : public Base {
- public:
- int foo1() override;
-
- // not_tail_called on a virtual function is an error.
- [[clang::not_tail_called]] int foo2() override;
- };
-
-
-#pragma omp declare simd
-------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","", "X"
-
-The `declare simd` construct can be applied to a function to enable the creation
-of one or more versions that can process multiple arguments using SIMD
-instructions from a single invocation in a SIMD loop. The `declare simd`
-directive is a declarative directive. There may be multiple `declare simd`
-directives for a function. The use of a `declare simd` construct on a function
-enables the creation of SIMD versions of the associated function that can be
-used to process multiple arguments from a single invocation from a SIMD loop
-concurrently.
-The syntax of the `declare simd` construct is as follows:
-
- .. code-block:: c
-
- #pragma omp declare simd [clause[[,] clause] ...] new-line
- [#pragma omp declare simd [clause[[,] clause] ...] new-line]
- [...]
- function definition or declaration
-
-where clause is one of the following:
-
- .. code-block:: c
-
- simdlen(length)
- linear(argument-list[:constant-linear-step])
- aligned(argument-list[:alignment])
- uniform(argument-list)
- inbranch
- notinbranch
-
-
-#pragma omp declare target
---------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","", "X"
-
-The `declare target` directive specifies that variables and functions are mapped
-to a device for OpenMP offload mechanism.
-
-The syntax of the declare target directive is as follows:
-
- .. code-block:: c
-
- #pragma omp declare target new-line
- declarations-definition-seq
- #pragma omp end declare target new-line
-
-
-objc_boxable
-------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Structs and unions marked with the ``objc_boxable`` attribute can be used
-with the Objective-C boxed expression syntax, ``@(...)``.
-
-**Usage**: ``__attribute__((objc_boxable))``. This attribute
-can only be placed on a declaration of a trivially-copyable struct or union:
-
-.. code-block:: objc
-
- struct __attribute__((objc_boxable)) some_struct {
- int i;
- };
- union __attribute__((objc_boxable)) some_union {
- int i;
- float f;
- };
- typedef struct __attribute__((objc_boxable)) _some_struct some_struct;
-
- // ...
-
- some_struct ss;
- NSValue *boxed = @(ss);
-
-
-objc_method_family
-------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Many methods in Objective-C have conventional meanings determined by their
-selectors. It is sometimes useful to be able to mark a method as having a
-particular conventional meaning despite not having the right selector, or as
-not having the conventional meaning that its selector would suggest. For these
-use cases, we provide an attribute to specifically describe the "method family"
-that a method belongs to.
-
-**Usage**: ``__attribute__((objc_method_family(X)))``, where ``X`` is one of
-``none``, ``alloc``, ``copy``, ``init``, ``mutableCopy``, or ``new``. This
-attribute can only be placed at the end of a method declaration:
-
-.. code-block:: objc
-
- - (NSString *)initMyStringValue __attribute__((objc_method_family(none)));
-
-Users who do not wish to change the conventional meaning of a method, and who
-merely want to document its non-standard retain and release semantics, should
-use the retaining behavior attributes (``ns_returns_retained``,
-``ns_returns_not_retained``, etc).
-
-Query for this feature with ``__has_attribute(objc_method_family)``.
-
-
-objc_requires_super
--------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Some Objective-C classes allow a subclass to override a particular method in a
-parent class but expect that the overriding method also calls the overridden
-method in the parent class. For these cases, we provide an attribute to
-designate that a method requires a "call to ``super``" in the overriding
-method in the subclass.
-
-**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only
-be placed at the end of a method declaration:
-
-.. code-block:: objc
-
- - (void)foo __attribute__((objc_requires_super));
-
-This attribute can only be applied the method declarations within a class, and
-not a protocol. Currently this attribute does not enforce any placement of
-where the call occurs in the overriding method (such as in the case of
-``-dealloc`` where the call must appear at the end). It checks only that it
-exists.
-
-Note that on both OS X and iOS that the Foundation framework provides a
-convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this
-attribute:
-
-.. code-block:: objc
-
- - (void)foo NS_REQUIRES_SUPER;
-
-This macro is conditionally defined depending on the compiler's support for
-this attribute. If the compiler does not support the attribute the macro
-expands to nothing.
-
-Operationally, when a method has this annotation the compiler will warn if the
-implementation of an override in a subclass does not call super. For example:
-
-.. code-block:: objc
-
- warning: method possibly missing a [super AnnotMeth] call
- - (void) AnnotMeth{};
- ^
-
-
-objc_runtime_name
------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-By default, the Objective-C interface or protocol identifier is used
-in the metadata name for that object. The `objc_runtime_name`
-attribute allows annotated interfaces or protocols to use the
-specified string argument in the object's metadata name instead of the
-default name.
-
-**Usage**: ``__attribute__((objc_runtime_name("MyLocalName")))``. This attribute
-can only be placed before an @protocol or @interface declaration:
-
-.. code-block:: objc
-
- __attribute__((objc_runtime_name("MyLocalName")))
- @interface Message
- @end
-
-
-objc_runtime_visible
---------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-This attribute specifies that the Objective-C class to which it applies is visible to the Objective-C runtime but not to the linker. Classes annotated with this attribute cannot be subclassed and cannot have categories defined for them.
-
-
-optnone (clang::optnone)
-------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``optnone`` attribute suppresses essentially all optimizations
-on a function or method, regardless of the optimization level applied to
-the compilation unit as a whole. This is particularly useful when you
-need to debug a particular function, but it is infeasible to build the
-entire application without optimization. Avoiding optimization on the
-specified function can improve the quality of the debugging information
-for that function.
-
-This attribute is incompatible with the ``always_inline`` and ``minsize``
-attributes.
-
-
-overloadable
-------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Clang provides support for C++ function overloading in C. Function overloading
-in C is introduced using the ``overloadable`` attribute. For example, one
-might provide several overloaded versions of a ``tgsin`` function that invokes
-the appropriate standard function computing the sine of a value with ``float``,
-``double``, or ``long double`` precision:
-
-.. code-block:: c
-
- #include <math.h>
- float __attribute__((overloadable)) tgsin(float x) { return sinf(x); }
- double __attribute__((overloadable)) tgsin(double x) { return sin(x); }
- long double __attribute__((overloadable)) tgsin(long double x) { return sinl(x); }
-
-Given these declarations, one can call ``tgsin`` with a ``float`` value to
-receive a ``float`` result, with a ``double`` to receive a ``double`` result,
-etc. Function overloading in C follows the rules of C++ function overloading
-to pick the best overload given the call arguments, with a few C-specific
-semantics:
-
-* Conversion from ``float`` or ``double`` to ``long double`` is ranked as a
- floating-point promotion (per C99) rather than as a floating-point conversion
- (as in C++).
-
-* A conversion from a pointer of type ``T*`` to a pointer of type ``U*`` is
- considered a pointer conversion (with conversion rank) if ``T`` and ``U`` are
- compatible types.
-
-* A conversion from type ``T`` to a value of type ``U`` is permitted if ``T``
- and ``U`` are compatible types. This conversion is given "conversion" rank.
-
-* If no viable candidates are otherwise available, we allow a conversion from a
- pointer of type ``T*`` to a pointer of type ``U*``, where ``T`` and ``U`` are
- incompatible. This conversion is ranked below all other types of conversions.
- Please note: ``U`` lacking qualifiers that are present on ``T`` is sufficient
- for ``T`` and ``U`` to be incompatible.
-
-The declaration of ``overloadable`` functions is restricted to function
-declarations and definitions. Most importantly, if any function with a given
-name is given the ``overloadable`` attribute, then all function declarations
-and definitions with that name (and in that scope) must have the
-``overloadable`` attribute. This rule even applies to redeclarations of
-functions whose original declaration had the ``overloadable`` attribute, e.g.,
-
-.. code-block:: c
-
- int f(int) __attribute__((overloadable));
- float f(float); // error: declaration of "f" must have the "overloadable" attribute
-
- int g(int) __attribute__((overloadable));
- int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute
-
-Functions marked ``overloadable`` must have prototypes. Therefore, the
-following code is ill-formed:
-
-.. code-block:: c
-
- int h() __attribute__((overloadable)); // error: h does not have a prototype
-
-However, ``overloadable`` functions are allowed to use a ellipsis even if there
-are no named parameters (as is permitted in C++). This feature is particularly
-useful when combined with the ``unavailable`` attribute:
-
-.. code-block:: c++
-
- void honeypot(...) __attribute__((overloadable, unavailable)); // calling me is an error
-
-Functions declared with the ``overloadable`` attribute have their names mangled
-according to the same rules as C++ function names. For example, the three
-``tgsin`` functions in our motivating example get the mangled names
-``_Z5tgsinf``, ``_Z5tgsind``, and ``_Z5tgsine``, respectively. There are two
-caveats to this use of name mangling:
-
-* Future versions of Clang may change the name mangling of functions overloaded
- in C, so you should not depend on an specific mangling. To be completely
- safe, we strongly urge the use of ``static inline`` with ``overloadable``
- functions.
-
-* The ``overloadable`` attribute has almost no meaning when used in C++,
- because names will already be mangled and functions are already overloadable.
- However, when an ``overloadable`` function occurs within an ``extern "C"``
- linkage specification, it's name *will* be mangled in the same way as it
- would in C.
-
-Query for this feature with ``__has_extension(attribute_overloadable)``.
-
-
-release_capability (release_shared_capability, clang::release_capability, clang::release_shared_capability)
------------------------------------------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Marks a function as releasing a capability.
-
-
-kernel
-------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-``__attribute__((kernel))`` is used to mark a ``kernel`` function in
-RenderScript.
-
-In RenderScript, ``kernel`` functions are used to express data-parallel
-computations. The RenderScript runtime efficiently parallelizes ``kernel``
-functions to run on computational resources such as multi-core CPUs and GPUs.
-See the RenderScript_ documentation for more information.
-
-.. _RenderScript: https://developer.android.com/guide/topics/renderscript/compute.html
-
-
-target (gnu::target)
---------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Clang supports the GNU style ``__attribute__((target("OPTIONS")))`` attribute.
-This attribute may be attached to a function definition and instructs
-the backend to use different code generation options than were passed on the
-command line.
-
-The current set of options correspond to the existing "subtarget features" for
-the target with or without a "-mno-" in front corresponding to the absence
-of the feature, as well as ``arch="CPU"`` which will change the default "CPU"
-for the function.
-
-Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2",
-"avx", "xop" and largely correspond to the machine specific options handled by
-the front end.
-
-
-try_acquire_capability (try_acquire_shared_capability, clang::try_acquire_capability, clang::try_acquire_shared_capability)
----------------------------------------------------------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Marks a function that attempts to acquire a capability. This function may fail to
-actually acquire the capability; they accept a Boolean value determining
-whether acquiring the capability means success (true), or failing to acquire
-the capability means success (false).
-
-
-nodiscard, warn_unused_result, clang::warn_unused_result, gnu::warn_unused_result
----------------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-Clang supports the ability to diagnose when the results of a function call
-expression are discarded under suspicious circumstances. A diagnostic is
-generated when a function or its return type is marked with ``[[nodiscard]]``
-(or ``__attribute__((warn_unused_result))``) and the function call appears as a
-potentially-evaluated discarded-value expression that is not explicitly cast to
-`void`.
-
-.. code-block: c++
- struct [[nodiscard]] error_info { /*...*/ };
- error_info enable_missile_safety_mode();
-
- void launch_missiles();
- void test_missiles() {
- enable_missile_safety_mode(); // diagnoses
- launch_missiles();
- }
- error_info &foo();
- void f() { foo(); } // Does not diagnose, error_info is a reference.
-
-
-xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument)
-------------------------------------------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching.
-
-Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points.
-
-If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise.
-
-
-Variable Attributes
-===================
-
-
-dllexport (gnu::dllexport)
---------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","X","", ""
-
-The ``__declspec(dllexport)`` attribute declares a variable, function, or
-Objective-C interface to be exported from the module. It is available under the
-``-fdeclspec`` flag for compatibility with various compilers. The primary use
-is for COFF object files which explicitly specify what interfaces are available
-for external use. See the dllexport_ documentation on MSDN for more
-information.
-
-.. _dllexport: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx
-
-
-dllimport (gnu::dllimport)
---------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","X","", ""
-
-The ``__declspec(dllimport)`` attribute declares a variable, function, or
-Objective-C interface to be imported from an external module. It is available
-under the ``-fdeclspec`` flag for compatibility with various compilers. The
-primary use is for COFF object files which explicitly specify what interfaces
-are imported from external modules. See the dllimport_ documentation on MSDN
-for more information.
-
-.. _dllimport: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx
-
-
-init_seg
---------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","", "X"
-
-The attribute applied by ``pragma init_seg()`` controls the section into
-which global initialization function pointers are emitted. It is only
-available with ``-fms-extensions``. Typically, this function pointer is
-emitted into ``.CRT$XCU`` on Windows. The user can change the order of
-initialization by using a different section name with the same
-``.CRT$XC`` prefix and a suffix that sorts lexicographically before or
-after the standard ``.CRT$XCU`` sections. See the init_seg_
-documentation on MSDN for more information.
-
-.. _init_seg: http://msdn.microsoft.com/en-us/library/7977wcck(v=vs.110).aspx
-
-
-nodebug (gnu::nodebug)
-----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``nodebug`` attribute allows you to suppress debugging information for a
-function or method, or for a variable that is not a parameter or a non-static
-data member.
-
-
-nosvm
------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-OpenCL 2.0 supports the optional ``__attribute__((nosvm))`` qualifier for
-pointer variable. It informs the compiler that the pointer does not refer
-to a shared virtual memory region. See OpenCL v2.0 s6.7.2 for details.
-
-Since it is not widely used and has been removed from OpenCL 2.1, it is ignored
-by Clang.
-
-
-pass_object_size
-----------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-.. Note:: The mangling of functions with parameters that are annotated with
- ``pass_object_size`` is subject to change. You can get around this by
- using ``__asm__("foo")`` to explicitly name your functions, thus preserving
- your ABI; also, non-overloadable C functions with ``pass_object_size`` are
- not mangled.
-
-The ``pass_object_size(Type)`` attribute can be placed on function parameters to
-instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite
-of said function, and implicitly pass the result of this call in as an invisible
-argument of type ``size_t`` directly after the parameter annotated with
-``pass_object_size``. Clang will also replace any calls to
-``__builtin_object_size(param, Type)`` in the function by said implicit
-parameter.
-
-Example usage:
-
-.. code-block:: c
-
- int bzero1(char *const p __attribute__((pass_object_size(0))))
- __attribute__((noinline)) {
- int i = 0;
- for (/**/; i < (int)__builtin_object_size(p, 0); ++i) {
- p[i] = 0;
- }
- return i;
- }
-
- int main() {
- char chars[100];
- int n = bzero1(&chars[0]);
- assert(n == sizeof(chars));
- return 0;
- }
-
-If successfully evaluating ``__builtin_object_size(param, Type)`` at the
-callsite is not possible, then the "failed" value is passed in. So, using the
-definition of ``bzero1`` from above, the following code would exit cleanly:
-
-.. code-block:: c
-
- int main2(int argc, char *argv[]) {
- int n = bzero1(argv);
- assert(n == -1);
- return 0;
- }
-
-``pass_object_size`` plays a part in overload resolution. If two overload
-candidates are otherwise equally good, then the overload with one or more
-parameters with ``pass_object_size`` is preferred. This implies that the choice
-between two identical overloads both with ``pass_object_size`` on one or more
-parameters will always be ambiguous; for this reason, having two such overloads
-is illegal. For example:
-
-.. code-block:: c++
-
- #define PS(N) __attribute__((pass_object_size(N)))
- // OK
- void Foo(char *a, char *b); // Overload A
- // OK -- overload A has no parameters with pass_object_size.
- void Foo(char *a PS(0), char *b PS(0)); // Overload B
- // Error -- Same signature (sans pass_object_size) as overload B, and both
- // overloads have one or more parameters with the pass_object_size attribute.
- void Foo(void *a PS(0), void *b);
-
- // OK
- void Bar(void *a PS(0)); // Overload C
- // OK
- void Bar(char *c PS(1)); // Overload D
-
- void main() {
- char known[10], *unknown;
- Foo(unknown, unknown); // Calls overload B
- Foo(known, unknown); // Calls overload B
- Foo(unknown, known); // Calls overload B
- Foo(known, known); // Calls overload B
-
- Bar(known); // Calls overload D
- Bar(unknown); // Calls overload D
- }
-
-Currently, ``pass_object_size`` is a bit restricted in terms of its usage:
-
-* Only one use of ``pass_object_size`` is allowed per parameter.
-
-* It is an error to take the address of a function with ``pass_object_size`` on
- any of its parameters. If you wish to do this, you can create an overload
- without ``pass_object_size`` on any parameters.
-
-* It is an error to apply the ``pass_object_size`` attribute to parameters that
- are not pointers. Additionally, any parameter that ``pass_object_size`` is
- applied to must be marked ``const`` at its function's definition.
-
-
-require_constant_initialization (clang::require_constant_initialization)
-------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-This attribute specifies that the variable to which it is attached is intended
-to have a `constant initializer <http://en.cppreference.com/w/cpp/language/constant_initialization>`_
-according to the rules of [basic.start.static]. The variable is required to
-have static or thread storage duration. If the initialization of the variable
-is not a constant initializer an error will be produced. This attribute may
-only be used in C++.
-
-Note that in C++03 strict constant expression checking is not done. Instead
-the attribute reports if Clang can emit the variable as a constant, even if it's
-not technically a 'constant initializer'. This behavior is non-portable.
-
-Static storage duration variables with constant initializers avoid hard-to-find
-bugs caused by the indeterminate order of dynamic initialization. They can also
-be safely used during dynamic initialization across translation units.
-
-This attribute acts as a compile time assertion that the requirements
-for constant initialization have been met. Since these requirements change
-between dialects and have subtle pitfalls it's important to fail fast instead
-of silently falling back on dynamic initialization.
-
-.. code-block:: c++
-
- // -std=c++14
- #define SAFE_STATIC [[clang::require_constant_initialization]]
- struct T {
- constexpr T(int) {}
- ~T(); // non-trivial
- };
- SAFE_STATIC T x = {42}; // Initialization OK. Doesn't check destructor.
- SAFE_STATIC T y = 42; // error: variable does not have a constant initializer
- // copy initialization is not a constant expression on a non-literal type.
-
-
-section (gnu::section, __declspec(allocate))
---------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","X","", ""
-
-The ``section`` attribute allows you to specify a specific section a
-global variable or function should be in after translation.
-
-
-swiftcall (gnu::swiftcall)
---------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``swiftcall`` attribute indicates that a function should be called
-using the Swift calling convention for a function or function pointer.
-
-The lowering for the Swift calling convention, as described by the Swift
-ABI documentation, occurs in multiple phases. The first, "high-level"
-phase breaks down the formal parameters and results into innately direct
-and indirect components, adds implicit paraameters for the generic
-signature, and assigns the context and error ABI treatments to parameters
-where applicable. The second phase breaks down the direct parameters
-and results from the first phase and assigns them to registers or the
-stack. The ``swiftcall`` convention only handles this second phase of
-lowering; the C function type must accurately reflect the results
-of the first phase, as follows:
-
-- Results classified as indirect by high-level lowering should be
- represented as parameters with the ``swift_indirect_result`` attribute.
-
-- Results classified as direct by high-level lowering should be represented
- as follows:
-
- - First, remove any empty direct results.
-
- - If there are no direct results, the C result type should be ``void``.
-
- - If there is one direct result, the C result type should be a type with
- the exact layout of that result type.
-
- - If there are a multiple direct results, the C result type should be
- a struct type with the exact layout of a tuple of those results.
-
-- Parameters classified as indirect by high-level lowering should be
- represented as parameters of pointer type.
-
-- Parameters classified as direct by high-level lowering should be
- omitted if they are empty types; otherwise, they should be represented
- as a parameter type with a layout exactly matching the layout of the
- Swift parameter type.
-
-- The context parameter, if present, should be represented as a trailing
- parameter with the ``swift_context`` attribute.
-
-- The error result parameter, if present, should be represented as a
- trailing parameter (always following a context parameter) with the
- ``swift_error_result`` attribute.
-
-``swiftcall`` does not support variadic arguments or unprototyped functions.
-
-The parameter ABI treatment attributes are aspects of the function type.
-A function type which which applies an ABI treatment attribute to a
-parameter is a different type from an otherwise-identical function type
-that does not. A single parameter may not have multiple ABI treatment
-attributes.
-
-Support for this feature is target-dependent, although it should be
-supported on every target that Swift supports. Query for this support
-with ``__has_attribute(swiftcall)``. This implies support for the
-``swift_context``, ``swift_error_result``, and ``swift_indirect_result``
-attributes.
-
-
-swift_context (gnu::swift_context)
-----------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``swift_context`` attribute marks a parameter of a ``swiftcall``
-function as having the special context-parameter ABI treatment.
-
-This treatment generally passes the context value in a special register
-which is normally callee-preserved.
-
-A ``swift_context`` parameter must either be the last parameter or must be
-followed by a ``swift_error_result`` parameter (which itself must always be
-the last parameter).
-
-A context parameter must have pointer or reference type.
-
-
-swift_error_result (gnu::swift_error_result)
---------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``swift_error_result`` attribute marks a parameter of a ``swiftcall``
-function as having the special error-result ABI treatment.
-
-This treatment generally passes the underlying error value in and out of
-the function through a special register which is normally callee-preserved.
-This is modeled in C by pretending that the register is addressable memory:
-
-- The caller appears to pass the address of a variable of pointer type.
- The current value of this variable is copied into the register before
- the call; if the call returns normally, the value is copied back into the
- variable.
-
-- The callee appears to receive the address of a variable. This address
- is actually a hidden location in its own stack, initialized with the
- value of the register upon entry. When the function returns normally,
- the value in that hidden location is written back to the register.
-
-A ``swift_error_result`` parameter must be the last parameter, and it must be
-preceded by a ``swift_context`` parameter.
-
-A ``swift_error_result`` parameter must have type ``T**`` or ``T*&`` for some
-type T. Note that no qualifiers are permitted on the intermediate level.
-
-It is undefined behavior if the caller does not pass a pointer or
-reference to a valid object.
-
-The standard convention is that the error value itself (that is, the
-value stored in the apparent argument) will be null upon function entry,
-but this is not enforced by the ABI.
-
-
-swift_indirect_result (gnu::swift_indirect_result)
---------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``swift_indirect_result`` attribute marks a parameter of a ``swiftcall``
-function as having the special indirect-result ABI treatment.
-
-This treatment gives the parameter the target's normal indirect-result
-ABI treatment, which may involve passing it differently from an ordinary
-parameter. However, only the first indirect result will receive this
-treatment. Furthermore, low-level lowering may decide that a direct result
-must be returned indirectly; if so, this will take priority over the
-``swift_indirect_result`` parameters.
-
-A ``swift_indirect_result`` parameter must either be the first parameter or
-follow another ``swift_indirect_result`` parameter.
-
-A ``swift_indirect_result`` parameter must have type ``T*`` or ``T&`` for
-some object type ``T``. If ``T`` is a complete type at the point of
-definition of a function, it is undefined behavior if the argument
-value does not point to storage of adequate size and alignment for a
-value of type ``T``.
-
-Making indirect results explicit in the signature allows C functions to
-directly construct objects into them without relying on language
-optimizations like C++'s named return value optimization (NRVO).
-
-
-tls_model (gnu::tls_model)
---------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``tls_model`` attribute allows you to specify which thread-local storage
-model to use. It accepts the following strings:
-
-* global-dynamic
-* local-dynamic
-* initial-exec
-* local-exec
-
-TLS models are mutually exclusive.
-
-
-thread
-------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","X","", ""
-
-The ``__declspec(thread)`` attribute declares a variable with thread local
-storage. It is available under the ``-fms-extensions`` flag for MSVC
-compatibility. See the documentation for `__declspec(thread)`_ on MSDN.
-
-.. _`__declspec(thread)`: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
-
-In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the
-GNU ``__thread`` keyword. The variable must not have a destructor and must have
-a constant initializer, if any. The attribute only applies to variables
-declared with static storage duration, such as globals, class static data
-members, and static locals.
-
-
-maybe_unused, unused, gnu::unused
----------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-When passing the ``-Wunused`` flag to Clang, entities that are unused by the
-program may be diagnosed. The ``[[maybe_unused]]`` (or
-``__attribute__((unused))``) attribute can be used to silence such diagnostics
-when the entity cannot be removed. For instance, a local variable may exist
-solely for use in an ``assert()`` statement, which makes the local variable
-unused when ``NDEBUG`` is defined.
-
-The attribute may be applied to the declaration of a class, a typedef, a
-variable, a function or method, a function parameter, an enumeration, an
-enumerator, a non-static data member, or a label.
-
-.. code-block: c++
- #include <cassert>
-
- [[maybe_unused]] void f([[maybe_unused]] bool thing1,
- [[maybe_unused]] bool thing2) {
- [[maybe_unused]] bool b = thing1 && thing2;
- assert(b);
- }
-
-
-Type Attributes
-===============
-
-
-align_value
------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-The align_value attribute can be added to the typedef of a pointer type or the
-declaration of a variable of pointer or reference type. It specifies that the
-pointer will point to, or the reference will bind to, only objects with at
-least the provided alignment. This alignment value must be some positive power
-of 2.
-
- .. code-block:: c
-
- typedef double * aligned_double_ptr __attribute__((align_value(64)));
- void foo(double & x __attribute__((align_value(128)),
- aligned_double_ptr y) { ... }
-
-If the pointer value does not have the specified alignment at runtime, the
-behavior of the program is undefined.
-
-
-empty_bases
------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","X","", ""
-
-The empty_bases attribute permits the compiler to utilize the
-empty-base-optimization more frequently.
-This attribute only applies to struct, class, and union types.
-It is only supported when using the Microsoft C++ ABI.
-
-
-flag_enum
----------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-This attribute can be added to an enumerator to signal to the compiler that it
-is intended to be used as a flag type. This will cause the compiler to assume
-that the range of the type includes all of the values that you can get by
-manipulating bits of the enumerator when issuing warnings.
-
-
-lto_visibility_public (clang::lto_visibility_public)
-----------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","X","","", ""
-
-See :doc:`LTOVisibility`.
-
-
-layout_version
---------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","X","", ""
-
-The layout_version attribute requests that the compiler utilize the class
-layout rules of a particular compiler version.
-This attribute only applies to struct, class, and union types.
-It is only supported when using the Microsoft C++ ABI.
-
-
-__single_inhertiance, __multiple_inheritance, __virtual_inheritance
--------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-This collection of keywords is enabled under ``-fms-extensions`` and controls
-the pointer-to-member representation used on ``*-*-win32`` targets.
-
-The ``*-*-win32`` targets utilize a pointer-to-member representation which
-varies in size and alignment depending on the definition of the underlying
-class.
-
-However, this is problematic when a forward declaration is only available and
-no definition has been made yet. In such cases, Clang is forced to utilize the
-most general representation that is available to it.
-
-These keywords make it possible to use a pointer-to-member representation other
-than the most general one regardless of whether or not the definition will ever
-be present in the current translation unit.
-
-This family of keywords belong between the ``class-key`` and ``class-name``:
-
-.. code-block:: c++
-
- struct __single_inheritance S;
- int S::*i;
- struct S {};
-
-This keyword can be applied to class templates but only has an effect when used
-on full specializations:
-
-.. code-block:: c++
-
- template <typename T, typename U> struct __single_inheritance A; // warning: inheritance model ignored on primary template
- template <typename T> struct __multiple_inheritance A<T, T>; // warning: inheritance model ignored on partial specialization
- template <> struct __single_inheritance A<int, float>;
-
-Note that choosing an inheritance model less general than strictly necessary is
-an error:
-
-.. code-block:: c++
-
- struct __multiple_inheritance S; // error: inheritance model does not match definition
- int S::*i;
- struct S {};
-
-
-novtable
---------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","X","", ""
-
-This attribute can be added to a class declaration or definition to signal to
-the compiler that constructors and destructors will not reference the virtual
-function table. It is only supported when using the Microsoft C++ ABI.
-
-
-objc_subclassing_restricted
----------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-This attribute can be added to an Objective-C ``@interface`` declaration to
-ensure that this class cannot be subclassed.
-
-
-transparent_union (gnu::transparent_union)
-------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-This attribute can be applied to a union to change the behaviour of calls to
-functions that have an argument with a transparent union type. The compiler
-behaviour is changed in the following manner:
-
-- A value whose type is any member of the transparent union can be passed as an
- argument without the need to cast that value.
-
-- The argument is passed to the function using the calling convention of the
- first member of the transparent union. Consequently, all the members of the
- transparent union should have the same calling convention as its first member.
-
-Transparent unions are not supported in C++.
-
-
-Statement Attributes
-====================
-
-
-fallthrough, clang::fallthrough
--------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","X","","", ""
-
-The ``fallthrough`` (or ``clang::fallthrough``) attribute is used
-to annotate intentional fall-through
-between switch labels. It can only be applied to a null statement placed at a
-point of execution between any statement and the next switch label. It is
-common to mark these places with a specific comment, but this attribute is
-meant to replace comments with a more strict annotation, which can be checked
-by the compiler. This attribute doesn't change semantics of the code and can
-be used wherever an intended fall-through occurs. It is designed to mimic
-control-flow statements like ``break;``, so it can be placed in most places
-where ``break;`` can, but only if there are no statements on the execution path
-between it and the next switch label.
-
-By default, Clang does not warn on unannotated fallthrough from one ``switch``
-case to another. Diagnostics on fallthrough without a corresponding annotation
-can be enabled with the ``-Wimplicit-fallthrough`` argument.
-
-Here is an example:
-
-.. code-block:: c++
-
- // compile with -Wimplicit-fallthrough
- switch (n) {
- case 22:
- case 33: // no warning: no statements between case labels
- f();
- case 44: // warning: unannotated fall-through
- g();
- [[clang::fallthrough]];
- case 55: // no warning
- if (x) {
- h();
- break;
- }
- else {
- i();
- [[clang::fallthrough]];
- }
- case 66: // no warning
- p();
- [[clang::fallthrough]]; // warning: fallthrough annotation does not
- // directly precede case label
- q();
- case 77: // warning: unannotated fall-through
- r();
- }
-
-
-#pragma clang loop
-------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","", "X"
-
-The ``#pragma clang loop`` directive allows loop optimization hints to be
-specified for the subsequent loop. The directive allows vectorization,
-interleaving, and unrolling to be enabled or disabled. Vector width as well
-as interleave and unrolling count can be manually specified. See
-`language extensions
-<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
-for details.
-
-
-#pragma unroll, #pragma nounroll
---------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","", "X"
-
-Loop unrolling optimization hints can be specified with ``#pragma unroll`` and
-``#pragma nounroll``. The pragma is placed immediately before a for, while,
-do-while, or c++11 range-based for loop.
-
-Specifying ``#pragma unroll`` without a parameter directs the loop unroller to
-attempt to fully unroll the loop if the trip count is known at compile time and
-attempt to partially unroll the loop if the trip count is not known at compile
-time:
-
-.. code-block:: c++
-
- #pragma unroll
- for (...) {
- ...
- }
-
-Specifying the optional parameter, ``#pragma unroll _value_``, directs the
-unroller to unroll the loop ``_value_`` times. The parameter may optionally be
-enclosed in parentheses:
-
-.. code-block:: c++
-
- #pragma unroll 16
- for (...) {
- ...
- }
-
- #pragma unroll(16)
- for (...) {
- ...
- }
-
-Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled:
-
-.. code-block:: c++
-
- #pragma nounroll
- for (...) {
- ...
- }
-
-``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to
-``#pragma clang loop unroll(full)`` and
-``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll``
-is equivalent to ``#pragma clang loop unroll(disable)``. See
-`language extensions
-<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
-for further details including limitations of the unroll hints.
-
-
-__read_only, __write_only, __read_write (read_only, write_only, read_write)
----------------------------------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The access qualifiers must be used with image object arguments or pipe arguments
-to declare if they are being read or written by a kernel or function.
-
-The read_only/__read_only, write_only/__write_only and read_write/__read_write
-names are reserved for use as access qualifiers and shall not be used otherwise.
-
-.. code-block:: c
-
- kernel void
- foo (read_only image2d_t imageA,
- write_only image2d_t imageB) {
- ...
- }
-
-In the above example imageA is a read-only 2D image object, and imageB is a
-write-only 2D image object.
-
-The read_write (or __read_write) qualifier can not be used with pipe.
-
-More details can be found in the OpenCL C language Spec v2.0, Section 6.6.
-
-
-__attribute__((opencl_unroll_hint))
------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-The opencl_unroll_hint attribute qualifier can be used to specify that a loop
-(for, while and do loops) can be unrolled. This attribute qualifier can be
-used to specify full unrolling or partial unrolling by a specified amount.
-This is a compiler hint and the compiler may ignore this directive. See
-`OpenCL v2.0 <https://www.khronos.org/registry/cl/specs/opencl-2.0.pdf>`_
-s6.11.5 for details.
-
-
-Type Safety Checking
-====================
-Clang supports additional attributes to enable checking type safety properties
-that can't be enforced by the C type system. To see warnings produced by these
-checks, ensure that -Wtype-safety is enabled. Use cases include:
-
-* MPI library implementations, where these attributes enable checking that
- the buffer type matches the passed ``MPI_Datatype``;
-* for HDF5 library there is a similar use case to MPI;
-* checking types of variadic functions' arguments for functions like
- ``fcntl()`` and ``ioctl()``.
-
-You can detect support for these attributes with ``__has_attribute()``. For
-example:
-
-.. code-block:: c++
-
- #if defined(__has_attribute)
- # if __has_attribute(argument_with_type_tag) && \
- __has_attribute(pointer_with_type_tag) && \
- __has_attribute(type_tag_for_datatype)
- # define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx)))
- /* ... other macros ... */
- # endif
- #endif
-
- #if !defined(ATTR_MPI_PWT)
- # define ATTR_MPI_PWT(buffer_idx, type_idx)
- #endif
-
- int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
- ATTR_MPI_PWT(1,3);
-
-argument_with_type_tag
-----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Use ``__attribute__((argument_with_type_tag(arg_kind, arg_idx,
-type_tag_idx)))`` on a function declaration to specify that the function
-accepts a type tag that determines the type of some other argument.
-
-This attribute is primarily useful for checking arguments of variadic functions
-(``pointer_with_type_tag`` can be used in most non-variadic cases).
-
-In the attribute prototype above:
- * ``arg_kind`` is an identifier that should be used when annotating all
- applicable type tags.
- * ``arg_idx`` provides the position of a function argument. The expected type of
- this function argument will be determined by the function argument specified
- by ``type_tag_idx``. In the code example below, "3" means that the type of the
- function's third argument will be determined by ``type_tag_idx``.
- * ``type_tag_idx`` provides the position of a function argument. This function
- argument will be a type tag. The type tag will determine the expected type of
- the argument specified by ``arg_idx``. In the code example below, "2" means
- that the type tag associated with the function's second argument should agree
- with the type of the argument specified by ``arg_idx``.
-
-For example:
-
-.. code-block:: c++
-
- int fcntl(int fd, int cmd, ...)
- __attribute__(( argument_with_type_tag(fcntl,3,2) ));
- // The function's second argument will be a type tag; this type tag will
- // determine the expected type of the function's third argument.
-
-
-pointer_with_type_tag
----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Use ``__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx, type_tag_idx)))``
-on a function declaration to specify that the function accepts a type tag that
-determines the pointee type of some other pointer argument.
-
-In the attribute prototype above:
- * ``ptr_kind`` is an identifier that should be used when annotating all
- applicable type tags.
- * ``ptr_idx`` provides the position of a function argument; this function
- argument will have a pointer type. The expected pointee type of this pointer
- type will be determined by the function argument specified by
- ``type_tag_idx``. In the code example below, "1" means that the pointee type
- of the function's first argument will be determined by ``type_tag_idx``.
- * ``type_tag_idx`` provides the position of a function argument; this function
- argument will be a type tag. The type tag will determine the expected pointee
- type of the pointer argument specified by ``ptr_idx``. In the code example
- below, "3" means that the type tag associated with the function's third
- argument should agree with the pointee type of the pointer argument specified
- by ``ptr_idx``.
-
-For example:
-
-.. code-block:: c++
-
- typedef int MPI_Datatype;
- int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
- __attribute__(( pointer_with_type_tag(mpi,1,3) ));
- // The function's 3rd argument will be a type tag; this type tag will
- // determine the expected pointee type of the function's 1st argument.
-
-
-type_tag_for_datatype
----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-When declaring a variable, use
-``__attribute__((type_tag_for_datatype(kind, type)))`` to create a type tag that
-is tied to the ``type`` argument given to the attribute.
-
-In the attribute prototype above:
- * ``kind`` is an identifier that should be used when annotating all applicable
- type tags.
- * ``type`` indicates the name of the type.
-
-Clang supports annotating type tags of two forms.
-
- * **Type tag that is a reference to a declared identifier.**
- Use ``__attribute__((type_tag_for_datatype(kind, type)))`` when declaring that
- identifier:
-
- .. code-block:: c++
-
- typedef int MPI_Datatype;
- extern struct mpi_datatype mpi_datatype_int
- __attribute__(( type_tag_for_datatype(mpi,int) ));
- #define MPI_INT ((MPI_Datatype) &mpi_datatype_int)
- // &mpi_datatype_int is a type tag. It is tied to type "int".
-
- * **Type tag that is an integral literal.**
- Declare a ``static const`` variable with an initializer value and attach
- ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration:
-
- .. code-block:: c++
-
- typedef int MPI_Datatype;
- static const MPI_Datatype mpi_datatype_int
- __attribute__(( type_tag_for_datatype(mpi,int) )) = 42;
- #define MPI_INT ((MPI_Datatype) 42)
- // The number 42 is a type tag. It is tied to type "int".
-
-
-The ``type_tag_for_datatype`` attribute also accepts an optional third argument
-that determines how the type of the function argument specified by either
-``arg_idx`` or ``ptr_idx`` is compared against the type associated with the type
-tag. (Recall that for the ``argument_with_type_tag`` attribute, the type of the
-function argument specified by ``arg_idx`` is compared against the type
-associated with the type tag. Also recall that for the ``pointer_with_type_tag``
-attribute, the pointee type of the function argument specified by ``ptr_idx`` is
-compared against the type associated with the type tag.) There are two supported
-values for this optional third argument:
-
- * ``layout_compatible`` will cause types to be compared according to
- layout-compatibility rules (In C++11 [class.mem] p 17, 18, see the
- layout-compatibility rules for two standard-layout struct types and for two
- standard-layout union types). This is useful when creating a type tag
- associated with a struct or union type. For example:
-
- .. code-block:: c++
-
- /* In mpi.h */
- typedef int MPI_Datatype;
- struct internal_mpi_double_int { double d; int i; };
- extern struct mpi_datatype mpi_datatype_double_int
- __attribute__(( type_tag_for_datatype(mpi,
- struct internal_mpi_double_int, layout_compatible) ));
-
- #define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int)
-
- int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...)
- __attribute__(( pointer_with_type_tag(mpi,1,3) ));
-
- /* In user code */
- struct my_pair { double a; int b; };
- struct my_pair *buffer;
- MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning because the
- // layout of my_pair is
- // compatible with that of
- // internal_mpi_double_int
-
- struct my_int_pair { int a; int b; }
- struct my_int_pair *buffer2;
- MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning because the
- // layout of my_int_pair
- // does not match that of
- // internal_mpi_double_int
-
- * ``must_be_null`` specifies that the function argument specified by either
- ``arg_idx`` (for the ``argument_with_type_tag`` attribute) or ``ptr_idx`` (for
- the ``pointer_with_type_tag`` attribute) should be a null pointer constant.
- The second argument to the ``type_tag_for_datatype`` attribute is ignored. For
- example:
-
- .. code-block:: c++
-
- /* In mpi.h */
- typedef int MPI_Datatype;
- extern struct mpi_datatype mpi_datatype_null
- __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) ));
-
- #define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null)
- int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...)
- __attribute__(( pointer_with_type_tag(mpi,1,3) ));
-
- /* In user code */
- struct my_pair { double a; int b; };
- struct my_pair *buffer;
- MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL
- // was specified but buffer
- // is not a null pointer
-
-
-AMD GPU Attributes
-==================
-
-
-amdgpu_flat_work_group_size
----------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-The flat work-group size is the number of work-items in the work-group size
-specified when the kernel is dispatched. It is the product of the sizes of the
-x, y, and z dimension of the work-group.
-
-Clang supports the
-``__attribute__((amdgpu_flat_work_group_size(<min>, <max>)))`` attribute for the
-AMDGPU target. This attribute may be attached to a kernel function definition
-and is an optimization hint.
-
-``<min>`` parameter specifies the minimum flat work-group size, and ``<max>``
-parameter specifies the maximum flat work-group size (must be greater than
-``<min>``) to which all dispatches of the kernel will conform. Passing ``0, 0``
-as ``<min>, <max>`` implies the default behavior (``128, 256``).
-
-If specified, the AMDGPU target backend might be able to produce better machine
-code for barriers and perform scratch promotion by estimating available group
-segment size.
-
-An error will be given if:
- - Specified values violate subtarget specifications;
- - Specified values are not compatible with values provided through other
- attributes.
-
-
-amdgpu_num_sgpr
----------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Clang supports the ``__attribute__((amdgpu_num_sgpr(<num_sgpr>)))`` and
-``__attribute__((amdgpu_num_vgpr(<num_vgpr>)))`` attributes for the AMDGPU
-target. These attributes may be attached to a kernel function definition and are
-an optimization hint.
-
-If these attributes are specified, then the AMDGPU target backend will attempt
-to limit the number of SGPRs and/or VGPRs used to the specified value(s). The
-number of used SGPRs and/or VGPRs may further be rounded up to satisfy the
-allocation requirements or constraints of the subtarget. Passing ``0`` as
-``num_sgpr`` and/or ``num_vgpr`` implies the default behavior (no limits).
-
-These attributes can be used to test the AMDGPU target backend. It is
-recommended that the ``amdgpu_waves_per_eu`` attribute be used to control
-resources such as SGPRs and VGPRs since it is aware of the limits for different
-subtargets.
-
-An error will be given if:
- - Specified values violate subtarget specifications;
- - Specified values are not compatible with values provided through other
- attributes;
- - The AMDGPU target backend is unable to create machine code that can meet the
- request.
-
-
-amdgpu_num_vgpr
----------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Clang supports the ``__attribute__((amdgpu_num_sgpr(<num_sgpr>)))`` and
-``__attribute__((amdgpu_num_vgpr(<num_vgpr>)))`` attributes for the AMDGPU
-target. These attributes may be attached to a kernel function definition and are
-an optimization hint.
-
-If these attributes are specified, then the AMDGPU target backend will attempt
-to limit the number of SGPRs and/or VGPRs used to the specified value(s). The
-number of used SGPRs and/or VGPRs may further be rounded up to satisfy the
-allocation requirements or constraints of the subtarget. Passing ``0`` as
-``num_sgpr`` and/or ``num_vgpr`` implies the default behavior (no limits).
-
-These attributes can be used to test the AMDGPU target backend. It is
-recommended that the ``amdgpu_waves_per_eu`` attribute be used to control
-resources such as SGPRs and VGPRs since it is aware of the limits for different
-subtargets.
-
-An error will be given if:
- - Specified values violate subtarget specifications;
- - Specified values are not compatible with values provided through other
- attributes;
- - The AMDGPU target backend is unable to create machine code that can meet the
- request.
-
-
-amdgpu_waves_per_eu
--------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-A compute unit (CU) is responsible for executing the wavefronts of a work-group.
-It is composed of one or more execution units (EU), which are responsible for
-executing the wavefronts. An EU can have enough resources to maintain the state
-of more than one executing wavefront. This allows an EU to hide latency by
-switching between wavefronts in a similar way to symmetric multithreading on a
-CPU. In order to allow the state for multiple wavefronts to fit on an EU, the
-resources used by a single wavefront have to be limited. For example, the number
-of SGPRs and VGPRs. Limiting such resources can allow greater latency hiding,
-but can result in having to spill some register state to memory.
-
-Clang supports the ``__attribute__((amdgpu_waves_per_eu(<min>[, <max>])))``
-attribute for the AMDGPU target. This attribute may be attached to a kernel
-function definition and is an optimization hint.
-
-``<min>`` parameter specifies the requested minimum number of waves per EU, and
-*optional* ``<max>`` parameter specifies the requested maximum number of waves
-per EU (must be greater than ``<min>`` if specified). If ``<max>`` is omitted,
-then there is no restriction on the maximum number of waves per EU other than
-the one dictated by the hardware for which the kernel is compiled. Passing
-``0, 0`` as ``<min>, <max>`` implies the default behavior (no limits).
-
-If specified, this attribute allows an advanced developer to tune the number of
-wavefronts that are capable of fitting within the resources of an EU. The AMDGPU
-target backend can use this information to limit resources, such as number of
-SGPRs, number of VGPRs, size of available group and private memory segments, in
-such a way that guarantees that at least ``<min>`` wavefronts and at most
-``<max>`` wavefronts are able to fit within the resources of an EU. Requesting
-more wavefronts can hide memory latency but limits available registers which
-can result in spilling. Requesting fewer wavefronts can help reduce cache
-thrashing, but can reduce memory latency hiding.
-
-This attribute controls the machine code generated by the AMDGPU target backend
-to ensure it is capable of meeting the requested values. However, when the
-kernel is executed, there may be other reasons that prevent meeting the request,
-for example, there may be wavefronts from other kernels executing on the EU.
-
-An error will be given if:
- - Specified values violate subtarget specifications;
- - Specified values are not compatible with values provided through other
- attributes;
- - The AMDGPU target backend is unable to create machine code that can meet the
- request.
-
-
-Calling Conventions
-===================
-Clang supports several different calling conventions, depending on the target
-platform and architecture. The calling convention used for a function determines
-how parameters are passed, how results are returned to the caller, and other
-low-level details of calling a function.
-
-fastcall (gnu::fastcall, __fastcall, _fastcall)
------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","X", ""
-
-On 32-bit x86 targets, this attribute changes the calling convention of a
-function to use ECX and EDX as register parameters and clear parameters off of
-the stack on return. This convention does not support variadic calls or
-unprototyped functions in C, and has no effect on x86_64 targets. This calling
-convention is supported primarily for compatibility with existing code. Users
-seeking register parameters should use the ``regparm`` attribute, which does
-not require callee-cleanup. See the documentation for `__fastcall`_ on MSDN.
-
-.. _`__fastcall`: http://msdn.microsoft.com/en-us/library/6xa169sk.aspx
-
-
-ms_abi (gnu::ms_abi)
---------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-On non-Windows x86_64 targets, this attribute changes the calling convention of
-a function to match the default convention used on Windows x86_64. This
-attribute has no effect on Windows targets or non-x86_64 targets.
-
-
-pcs (gnu::pcs)
---------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-On ARM targets, this attribute can be used to select calling conventions
-similar to ``stdcall`` on x86. Valid parameter values are "aapcs" and
-"aapcs-vfp".
-
-
-preserve_all
-------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-On X86-64 and AArch64 targets, this attribute changes the calling convention of
-a function. The ``preserve_all`` calling convention attempts to make the code
-in the caller even less intrusive than the ``preserve_most`` calling convention.
-This calling convention also behaves identical to the ``C`` calling convention
-on how arguments and return values are passed, but it uses a different set of
-caller/callee-saved registers. This removes the burden of saving and
-recovering a large register set before and after the call in the caller. If
-the arguments are passed in callee-saved registers, then they will be
-preserved by the callee across the call. This doesn't apply for values
-returned in callee-saved registers.
-
-- On X86-64 the callee preserves all general purpose registers, except for
- R11. R11 can be used as a scratch register. Furthermore it also preserves
- all floating-point registers (XMMs/YMMs).
-
-The idea behind this convention is to support calls to runtime functions
-that don't need to call out to any other functions.
-
-This calling convention, like the ``preserve_most`` calling convention, will be
-used by a future version of the Objective-C runtime and should be considered
-experimental at this time.
-
-
-preserve_most
--------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-On X86-64 and AArch64 targets, this attribute changes the calling convention of
-a function. The ``preserve_most`` calling convention attempts to make the code
-in the caller as unintrusive as possible. This convention behaves identically
-to the ``C`` calling convention on how arguments and return values are passed,
-but it uses a different set of caller/callee-saved registers. This alleviates
-the burden of saving and recovering a large register set before and after the
-call in the caller. If the arguments are passed in callee-saved registers,
-then they will be preserved by the callee across the call. This doesn't
-apply for values returned in callee-saved registers.
-
-- On X86-64 the callee preserves all general purpose registers, except for
- R11. R11 can be used as a scratch register. Floating-point registers
- (XMMs/YMMs) are not preserved and need to be saved by the caller.
-
-The idea behind this convention is to support calls to runtime functions
-that have a hot path and a cold path. The hot path is usually a small piece
-of code that doesn't use many registers. The cold path might need to call out to
-another function and therefore only needs to preserve the caller-saved
-registers, which haven't already been saved by the caller. The
-`preserve_most` calling convention is very similar to the ``cold`` calling
-convention in terms of caller/callee-saved registers, but they are used for
-different types of function calls. ``coldcc`` is for function calls that are
-rarely executed, whereas `preserve_most` function calls are intended to be
-on the hot path and definitely executed a lot. Furthermore ``preserve_most``
-doesn't prevent the inliner from inlining the function call.
-
-This calling convention will be used by a future version of the Objective-C
-runtime and should therefore still be considered experimental at this time.
-Although this convention was created to optimize certain runtime calls to
-the Objective-C runtime, it is not limited to this runtime and might be used
-by other runtimes in the future too. The current implementation only
-supports X86-64 and AArch64, but the intention is to support more architectures
-in the future.
-
-
-regcall (gnu::regcall, __regcall)
----------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","X", ""
-
-On x86 targets, this attribute changes the calling convention to
-`__regcall`_ convention. This convention aims to pass as many arguments
-as possible in registers. It also tries to utilize registers for the
-return value whenever it is possible.
-
-.. _`__regcall`: https://software.intel.com/en-us/node/693069
-
-
-regparm (gnu::regparm)
-----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-On 32-bit x86 targets, the regparm attribute causes the compiler to pass
-the first three integer parameters in EAX, EDX, and ECX instead of on the
-stack. This attribute has no effect on variadic functions, and all parameters
-are passed via the stack as normal.
-
-
-stdcall (gnu::stdcall, __stdcall, _stdcall)
--------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","X", ""
-
-On 32-bit x86 targets, this attribute changes the calling convention of a
-function to clear parameters off of the stack on return. This convention does
-not support variadic calls or unprototyped functions in C, and has no effect on
-x86_64 targets. This calling convention is used widely by the Windows API and
-COM applications. See the documentation for `__stdcall`_ on MSDN.
-
-.. _`__stdcall`: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx
-
-
-thiscall (gnu::thiscall, __thiscall, _thiscall)
------------------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","X", ""
-
-On 32-bit x86 targets, this attribute changes the calling convention of a
-function to use ECX for the first parameter (typically the implicit ``this``
-parameter of C++ methods) and clear parameters off of the stack on return. This
-convention does not support variadic calls or unprototyped functions in C, and
-has no effect on x86_64 targets. See the documentation for `__thiscall`_ on
-MSDN.
-
-.. _`__thiscall`: http://msdn.microsoft.com/en-us/library/ek8tkfbw.aspx
-
-
-vectorcall (__vectorcall, _vectorcall)
---------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","X", ""
-
-On 32-bit x86 *and* x86_64 targets, this attribute changes the calling
-convention of a function to pass vector parameters in SSE registers.
-
-On 32-bit x86 targets, this calling convention is similar to ``__fastcall``.
-The first two integer parameters are passed in ECX and EDX. Subsequent integer
-parameters are passed in memory, and callee clears the stack. On x86_64
-targets, the callee does *not* clear the stack, and integer parameters are
-passed in RCX, RDX, R8, and R9 as is done for the default Windows x64 calling
-convention.
-
-On both 32-bit x86 and x86_64 targets, vector and floating point arguments are
-passed in XMM0-XMM5. Homogeneous vector aggregates of up to four elements are
-passed in sequential SSE registers if enough are available. If AVX is enabled,
-256 bit vectors are passed in YMM0-YMM5. Any vector or aggregate type that
-cannot be passed in registers for any reason is passed by reference, which
-allows the caller to align the parameter memory.
-
-See the documentation for `__vectorcall`_ on MSDN for more details.
-
-.. _`__vectorcall`: http://msdn.microsoft.com/en-us/library/dn375768.aspx
-
-
-Consumed Annotation Checking
-============================
-Clang supports additional attributes for checking basic resource management
-properties, specifically for unique objects that have a single owning reference.
-The following attributes are currently supported, although **the implementation
-for these annotations is currently in development and are subject to change.**
-
-callable_when
--------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Use ``__attribute__((callable_when(...)))`` to indicate what states a method
-may be called in. Valid states are unconsumed, consumed, or unknown. Each
-argument to this attribute must be a quoted string. E.g.:
-
-``__attribute__((callable_when("unconsumed", "unknown")))``
-
-
-consumable
-----------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Each ``class`` that uses any of the typestate annotations must first be marked
-using the ``consumable`` attribute. Failure to do so will result in a warning.
-
-This attribute accepts a single parameter that must be one of the following:
-``unknown``, ``consumed``, or ``unconsumed``.
-
-
-param_typestate
----------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-This attribute specifies expectations about function parameters. Calls to an
-function with annotated parameters will issue a warning if the corresponding
-argument isn't in the expected state. The attribute is also used to set the
-initial state of the parameter when analyzing the function's body.
-
-
-return_typestate
-----------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-The ``return_typestate`` attribute can be applied to functions or parameters.
-When applied to a function the attribute specifies the state of the returned
-value. The function's body is checked to ensure that it always returns a value
-in the specified state. On the caller side, values returned by the annotated
-function are initialized to the given state.
-
-When applied to a function parameter it modifies the state of an argument after
-a call to the function returns. The function's body is checked to ensure that
-the parameter is in the expected state before returning.
-
-
-set_typestate
--------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Annotate methods that transition an object into a new state with
-``__attribute__((set_typestate(new_state)))``. The new state must be
-unconsumed, consumed, or unknown.
-
-
-test_typestate
---------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","","","", ""
-
-Use ``__attribute__((test_typestate(tested_state)))`` to indicate that a method
-returns true if the object is in the specified state..
-
-
-OpenCL Address Spaces
-=====================
-The address space qualifier may be used to specify the region of memory that is
-used to allocate the object. OpenCL supports the following address spaces:
-__generic(generic), __global(global), __local(local), __private(private),
-__constant(constant).
-
- .. code-block:: c
-
- __constant int c = ...;
-
- __generic int* foo(global int* g) {
- __local int* l;
- private int p;
- ...
- return l;
- }
-
-More details can be found in the OpenCL C language Spec v2.0, Section 6.5.
-
-constant (__constant)
----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The constant address space attribute signals that an object is located in
-a constant (non-modifiable) memory region. It is available to all work items.
-Any type can be annotated with the constant address space attribute. Objects
-with the constant address space qualifier can be declared in any scope and must
-have an initializer.
-
-
-generic (__generic)
--------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The generic address space attribute is only available with OpenCL v2.0 and later.
-It can be used with pointer types. Variables in global and local scope and
-function parameters in non-kernel functions can have the generic address space
-type attribute. It is intended to be a placeholder for any other address space
-except for '__constant' in OpenCL code which can be used with multiple address
-spaces.
-
-
-global (__global)
------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The global address space attribute specifies that an object is allocated in
-global memory, which is accessible by all work items. The content stored in this
-memory area persists between kernel executions. Pointer types to the global
-address space are allowed as function parameters or local variables. Starting
-with OpenCL v2.0, the global address space can be used with global (program
-scope) variables and static local variable as well.
-
-
-local (__local)
----------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The local address space specifies that an object is allocated in the local (work
-group) memory area, which is accessible to all work items in the same work
-group. The content stored in this memory region is not accessible after
-the kernel execution ends. In a kernel function scope, any variable can be in
-the local address space. In other scopes, only pointer types to the local address
-space are allowed. Local address space variables cannot have an initializer.
-
-
-private (__private)
--------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The private address space specifies that an object is allocated in the private
-(work item) memory. Other work items cannot access the same memory area and its
-content is destroyed after work item execution ends. Local variables can be
-declared in the private address space. Function arguments are always in the
-private address space. Kernel function arguments of a pointer or an array type
-cannot point to the private address space.
-
-
-Nullability Attributes
-======================
-Whether a particular pointer may be "null" is an important concern when working with pointers in the C family of languages. The various nullability attributes indicate whether a particular pointer can be null or not, which makes APIs more expressive and can help static analysis tools identify bugs involving null pointers. Clang supports several kinds of nullability attributes: the ``nonnull`` and ``returns_nonnull`` attributes indicate which function or method parameters and result types can never be null, while nullability type qualifiers indicate which pointer types can be null (``_Nullable``) or cannot be null (``_Nonnull``).
-
-The nullability (type) qualifiers express whether a value of a given pointer type can be null (the ``_Nullable`` qualifier), doesn't have a defined meaning for null (the ``_Nonnull`` qualifier), or for which the purpose of null is unclear (the ``_Null_unspecified`` qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the ``nonnull`` and ``returns_nonnull`` attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply. For example:
-
- .. code-block:: c
-
- // No meaningful result when 'ptr' is null (here, it happens to be undefined behavior).
- int fetch(int * _Nonnull ptr) { return *ptr; }
-
- // 'ptr' may be null.
- int fetch_or_zero(int * _Nullable ptr) {
- return ptr ? *ptr : 0;
- }
-
- // A nullable pointer to non-null pointers to const characters.
- const char *join_strings(const char * _Nonnull * _Nullable strings, unsigned n);
-
-In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords. For example:
-
- .. code-block:: objective-c
-
- @interface NSView : NSResponder
- - (nullable NSView *)ancestorSharedWithView:(nonnull NSView *)aView;
- @property (assign, nullable) NSView *superview;
- @property (readonly, nonnull) NSArray *subviews;
- @end
-
-nonnull (gnu::nonnull)
-----------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``nonnull`` attribute indicates that some function parameters must not be null, and can be used in several different ways. It's original usage (`from GCC <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes>`_) is as a function (or Objective-C method) attribute that specifies which parameters of the function are nonnull in a comma-separated list. For example:
-
- .. code-block:: c
-
- extern void * my_memcpy (void *dest, const void *src, size_t len)
- __attribute__((nonnull (1, 2)));
-
-Here, the ``nonnull`` attribute indicates that parameters 1 and 2
-cannot have a null value. Omitting the parenthesized list of parameter indices means that all parameters of pointer type cannot be null:
-
- .. code-block:: c
-
- extern void * my_memcpy (void *dest, const void *src, size_t len)
- __attribute__((nonnull));
-
-Clang also allows the ``nonnull`` attribute to be placed directly on a function (or Objective-C method) parameter, eliminating the need to specify the parameter index ahead of type. For example:
-
- .. code-block:: c
-
- extern void * my_memcpy (void *dest __attribute__((nonnull)),
- const void *src __attribute__((nonnull)), size_t len);
-
-Note that the ``nonnull`` attribute indicates that passing null to a non-null parameter is undefined behavior, which the optimizer may take advantage of to, e.g., remove null checks. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable.
-
-
-returns_nonnull (gnu::returns_nonnull)
---------------------------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "X","X","","", ""
-
-The ``returns_nonnull`` attribute indicates that a particular function (or Objective-C method) always returns a non-null pointer. For example, a particular system ``malloc`` might be defined to terminate a process when memory is not available rather than returning a null pointer:
-
- .. code-block:: c
-
- extern void * malloc (size_t size) __attribute__((returns_nonnull));
-
-The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable
-
-
-_Nonnull
---------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The ``_Nonnull`` nullability qualifier indicates that null is not a meaningful value for a value of the ``_Nonnull`` pointer type. For example, given a declaration such as:
-
- .. code-block:: c
-
- int fetch(int * _Nonnull ptr);
-
-a caller of ``fetch`` should not provide a null value, and the compiler will produce a warning if it sees a literal null value passed to ``fetch``. Note that, unlike the declaration attribute ``nonnull``, the presence of ``_Nonnull`` does not imply that passing null is undefined behavior: ``fetch`` is free to consider null undefined behavior or (perhaps for backward-compatibility reasons) defensively handle null.
-
-
-_Null_unspecified
------------------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The ``_Null_unspecified`` nullability qualifier indicates that neither the ``_Nonnull`` nor ``_Nullable`` qualifiers make sense for a particular pointer type. It is used primarily to indicate that the role of null with specific pointers in a nullability-annotated header is unclear, e.g., due to overly-complex implementations or historical factors with a long-lived API.
-
-
-_Nullable
----------
-.. csv-table:: Supported Syntaxes
- :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
-
- "","","","X", ""
-
-The ``_Nullable`` nullability qualifier indicates that a value of the ``_Nullable`` pointer type can be null. For example, given:
-
- .. code-block:: c
-
- int fetch_or_zero(int * _Nullable ptr);
-
-a caller of ``fetch_or_zero`` can provide null.
-
-
+=================== \ No newline at end of file
diff --git a/docs/ClangCommandLineReference.rst b/docs/ClangCommandLineReference.rst
new file mode 100644
index 000000000000..add168829e1b
--- /dev/null
+++ b/docs/ClangCommandLineReference.rst
@@ -0,0 +1,2591 @@
+..
+ -------------------------------------------------------------------
+ NOTE: This file is automatically generated by running clang-tblgen
+ -gen-opt-docs. Do not edit this file by hand!!
+ -------------------------------------------------------------------
+
+=====================================
+Clang command line argument reference
+=====================================
+.. contents::
+ :local:
+
+Introduction
+============
+
+This page lists the command line arguments currently supported by the
+GCC-compatible ``clang`` and ``clang++`` drivers.
+
+
+.. program:: clang
+.. option:: -B<dir>, --prefix <arg>, --prefix=<arg>
+
+Add <dir> to search path for binaries and object files used implicitly
+
+.. option:: -F<arg>
+
+Add directory to framework include search path
+
+.. option:: -ObjC
+
+Treat source input files as Objective-C inputs
+
+.. program:: clang1
+.. option:: -ObjC++
+.. program:: clang
+
+Treat source input files as Objective-C++ inputs
+
+.. option:: -Qunused-arguments
+
+Don't emit warning for unused driver arguments
+
+.. option:: -Wa,<arg>,<arg2>...
+
+Pass the comma separated arguments in <arg> to the assembler
+
+.. option:: -Wlarge-by-value-copy=<arg>
+
+.. option:: -Xarch\_<arg1> <arg2>
+
+.. option:: -Xcuda-fatbinary <arg>
+
+Pass <arg> to fatbinary invocation
+
+.. option:: -Xcuda-ptxas <arg>
+
+Pass <arg> to the ptxas assembler
+
+.. option:: -Z<arg>
+
+.. option:: -a<arg>, --profile-blocks
+
+.. option:: -all\_load
+
+.. option:: -allowable\_client <arg>
+
+.. option:: --analyze
+
+Run the static analyzer
+
+.. option:: --analyze-auto
+
+.. option:: --analyzer-no-default-checks
+
+.. option:: --analyzer-output<arg>
+
+Static analyzer report output format (html\|plist\|plist-multi-file\|plist-html\|text).
+
+.. option:: -ansi, --ansi
+
+.. option:: -arch <arg>
+
+.. program:: clang1
+.. option:: -arch\_errors\_fatal
+.. program:: clang
+
+.. program:: clang2
+.. option:: -arch\_only <arg>
+.. program:: clang
+
+.. option:: -arcmt-migrate-emit-errors
+
+Emit ARC errors even if the migrator can fix them
+
+.. option:: -arcmt-migrate-report-output <arg>
+
+Output path for the plist report
+
+.. option:: -bind\_at\_load
+
+.. option:: -bundle
+
+.. program:: clang1
+.. option:: -bundle\_loader <arg>
+.. program:: clang
+
+.. option:: -client\_name<arg>
+
+.. option:: -compatibility\_version<arg>
+
+.. option:: --constant-cfstrings
+
+.. option:: -coverage, --coverage
+
+.. option:: --cuda-compile-host-device
+
+Compile CUDA code for both host and device (default). Has no effect on non-CUDA compilations.
+
+.. option:: --cuda-device-only
+
+Compile CUDA code for device only
+
+.. option:: --cuda-gpu-arch=<arg>, --no-cuda-gpu-arch=<arg>
+
+CUDA GPU architecture (e.g. sm\_35). May be specified more than once.
+
+.. option:: --cuda-host-only
+
+Compile CUDA code for host only. Has no effect on non-CUDA compilations.
+
+.. option:: --cuda-noopt-device-debug, --no-cuda-noopt-device-debug
+
+Enable device-side debug info generation. Disables ptxas optimizations.
+
+.. option:: -current\_version<arg>
+
+.. option:: -dead\_strip
+
+.. option:: -dependency-dot <arg>
+
+Filename to write DOT-formatted header dependencies to
+
+.. option:: -dependency-file <arg>
+
+Filename (or -) to write dependency output to
+
+.. option:: -dumpmachine
+
+.. option:: -dumpversion
+
+.. option:: --dyld-prefix=<arg>, --dyld-prefix <arg>
+
+.. option:: -dylib\_file <arg>
+
+.. option:: -dylinker
+
+.. program:: clang1
+.. option:: -dylinker\_install\_name<arg>
+.. program:: clang
+
+.. option:: -dynamic
+
+.. option:: -dynamiclib
+
+.. option:: -emit-ast
+
+Emit Clang AST files for source inputs
+
+.. option:: -exported\_symbols\_list <arg>
+
+.. option:: -faligned-new=<arg>
+
+.. option:: -fcuda-approx-transcendentals, -fno-cuda-approx-transcendentals
+
+Use approximate transcendental functions
+
+.. option:: -fcuda-flush-denormals-to-zero, -fno-cuda-flush-denormals-to-zero
+
+Flush denormal floating point values to zero in CUDA device mode.
+
+.. option:: -fheinous-gnu-extensions
+
+.. option:: -flat\_namespace
+
+.. option:: -fopenmp-targets=<arg1>,<arg2>...
+
+Specify comma-separated list of triples OpenMP offloading targets to be supported
+
+.. option:: -force\_cpusubtype\_ALL
+
+.. program:: clang1
+.. option:: -force\_flat\_namespace
+.. program:: clang
+
+.. program:: clang2
+.. option:: -force\_load <arg>
+.. program:: clang
+
+.. option:: -framework <arg>
+
+.. option:: -frtlib-add-rpath, -fno-rtlib-add-rpath
+
+Add -rpath with architecture-specific resource directory to the linker flags
+
+.. option:: --gcc-toolchain=<arg>, -gcc-toolchain <arg>
+
+Use the gcc toolchain at the given directory
+
+.. option:: -gcodeview
+
+Generate CodeView debug information
+
+.. option:: -headerpad\_max\_install\_names<arg>
+
+.. option:: -help, --help
+
+Display available options
+
+.. option:: --help-hidden
+
+.. option:: -image\_base <arg>
+
+.. option:: -index-header-map
+
+Make the next included directory (-I or -F) an indexer header map
+
+.. option:: -init <arg>
+
+.. option:: -install\_name <arg>
+
+.. option:: -keep\_private\_externs
+
+.. option:: -lazy\_framework <arg>
+
+.. program:: clang1
+.. option:: -lazy\_library <arg>
+.. program:: clang
+
+.. option:: -mbig-endian, -EB
+
+.. option:: --migrate
+
+Run the migrator
+
+.. option:: -mios-simulator-version-min=<arg>, -miphonesimulator-version-min=<arg>
+
+.. option:: -mlinker-version=<arg>
+
+.. option:: -mlittle-endian, -EL
+
+.. option:: -mllvm <arg>
+
+Additional arguments to forward to LLVM's option processing
+
+.. option:: -module-dependency-dir <arg>
+
+Directory to dump module dependencies to
+
+.. option:: -mtvos-simulator-version-min=<arg>, -mappletvsimulator-version-min=<arg>
+
+.. option:: -multi\_module
+
+.. option:: -multiply\_defined <arg>
+
+.. program:: clang1
+.. option:: -multiply\_defined\_unused <arg>
+.. program:: clang
+
+.. option:: -mwatchos-simulator-version-min=<arg>, -mwatchsimulator-version-min=<arg>
+
+.. option:: --no-cuda-version-check
+
+Don't error out if the detected version of the CUDA install is too low for the requested CUDA gpu architecture.
+
+.. option:: -no-integrated-cpp, --no-integrated-cpp
+
+.. option:: -no\_dead\_strip\_inits\_and\_terms
+
+.. option:: -nobuiltininc
+
+Disable builtin #include directories
+
+.. option:: -nocudainc
+
+.. option:: -nocudalib
+
+.. option:: -nodefaultlibs
+
+.. option:: -nofixprebinding
+
+.. option:: -nolibc
+
+.. option:: -nomultidefs
+
+.. option:: -nopie
+
+.. option:: -noprebind
+
+.. option:: -noseglinkedit
+
+.. option:: -nostartfiles
+
+.. option:: -nostdinc, --no-standard-includes
+
+.. program:: clang1
+.. option:: -nostdinc++
+.. program:: clang
+
+Disable standard #include directories for the C++ standard library
+
+.. option:: -nostdlib, --no-standard-libraries
+
+.. option:: -nostdlibinc
+
+.. option:: -o<file>, --output <arg>, --output=<arg>
+
+Write output to <file>
+
+.. option:: -objcmt-atomic-property
+
+Make migration to 'atomic' properties
+
+.. option:: -objcmt-migrate-all
+
+Enable migration to modern ObjC
+
+.. option:: -objcmt-migrate-annotation
+
+Enable migration to property and method annotations
+
+.. option:: -objcmt-migrate-designated-init
+
+Enable migration to infer NS\_DESIGNATED\_INITIALIZER for initializer methods
+
+.. option:: -objcmt-migrate-instancetype
+
+Enable migration to infer instancetype for method result type
+
+.. option:: -objcmt-migrate-literals
+
+Enable migration to modern ObjC literals
+
+.. option:: -objcmt-migrate-ns-macros
+
+Enable migration to NS\_ENUM/NS\_OPTIONS macros
+
+.. option:: -objcmt-migrate-property
+
+Enable migration to modern ObjC property
+
+.. option:: -objcmt-migrate-property-dot-syntax
+
+Enable migration of setter/getter messages to property-dot syntax
+
+.. option:: -objcmt-migrate-protocol-conformance
+
+Enable migration to add protocol conformance on classes
+
+.. option:: -objcmt-migrate-readonly-property
+
+Enable migration to modern ObjC readonly property
+
+.. option:: -objcmt-migrate-readwrite-property
+
+Enable migration to modern ObjC readwrite property
+
+.. option:: -objcmt-migrate-subscripting
+
+Enable migration to modern ObjC subscripting
+
+.. option:: -objcmt-ns-nonatomic-iosonly
+
+Enable migration to use NS\_NONATOMIC\_IOSONLY macro for setting property's 'atomic' attribute
+
+.. option:: -objcmt-returns-innerpointer-property
+
+Enable migration to annotate property with NS\_RETURNS\_INNER\_POINTER
+
+.. option:: -objcmt-whitelist-dir-path=<arg>, -objcmt-white-list-dir-path=<arg>
+
+Only modify files with a filename contained in the provided directory path
+
+.. option:: -object
+
+.. option:: -p, --profile
+
+.. option:: -pagezero\_size<arg>
+
+.. option:: -pg
+
+Enable mcount instrumentation
+
+.. option:: -pie
+
+.. option:: -pipe, --pipe
+
+Use pipes between commands, when possible
+
+.. option:: -prebind
+
+.. program:: clang1
+.. option:: -prebind\_all\_twolevel\_modules
+.. program:: clang
+
+.. option:: -preload
+
+.. option:: --print-diagnostic-categories
+
+.. option:: -print-file-name=<file>, --print-file-name=<file>, --print-file-name <arg>
+
+Print the full library path of <file>
+
+.. option:: -print-ivar-layout
+
+Enable Objective-C Ivar layout bitmap print trace
+
+.. option:: -print-libgcc-file-name, --print-libgcc-file-name
+
+Print the library path for the currently used compiler runtime library ("libgcc.a" or "libclang\_rt.builtins.\*.a")
+
+.. option:: -print-multi-directory, --print-multi-directory
+
+.. option:: -print-multi-lib, --print-multi-lib
+
+.. option:: -print-prog-name=<name>, --print-prog-name=<name>, --print-prog-name <arg>
+
+Print the full program path of <name>
+
+.. option:: -print-resource-dir, --print-resource-dir
+
+Print the resource directory pathname
+
+.. option:: -print-search-dirs, --print-search-dirs
+
+Print the paths used for finding libraries and programs
+
+.. option:: -private\_bundle
+
+.. option:: -pthread, -no-pthread
+
+Support POSIX threads in generated code
+
+.. option:: -pthreads
+
+.. option:: -rdynamic
+
+.. option:: -read\_only\_relocs <arg>
+
+.. option:: -relocatable-pch, --relocatable-pch
+
+Whether to build a relocatable precompiled header
+
+.. option:: -remap
+
+.. option:: -rewrite-legacy-objc
+
+Rewrite Legacy Objective-C source to C++
+
+.. option:: -rtlib=<arg>, --rtlib=<arg>, --rtlib <arg>
+
+Compiler runtime library to use
+
+.. option:: -save-stats=<arg>, --save-stats=<arg>, -save-stats (equivalent to -save-stats=cwd), --save-stats (equivalent to -save-stats=cwd)
+
+Save llvm statistics.
+
+.. option:: -save-temps=<arg>, --save-temps=<arg>, -save-temps (equivalent to -save-temps=cwd), --save-temps (equivalent to -save-temps=cwd)
+
+Save intermediate compilation results.
+
+.. option:: -sectalign <arg1> <arg2> <arg3>
+
+.. option:: -sectcreate <arg1> <arg2> <arg3>
+
+.. option:: -sectobjectsymbols <arg1> <arg2>
+
+.. option:: -sectorder <arg1> <arg2> <arg3>
+
+.. option:: -seg1addr<arg>
+
+.. option:: -seg\_addr\_table <arg>
+
+.. program:: clang1
+.. option:: -seg\_addr\_table\_filename <arg>
+.. program:: clang
+
+.. option:: -segaddr <arg1> <arg2>
+
+.. option:: -segcreate <arg1> <arg2> <arg3>
+
+.. option:: -seglinkedit
+
+.. option:: -segprot <arg1> <arg2> <arg3>
+
+.. option:: -segs\_read\_<arg>
+
+.. program:: clang1
+.. option:: -segs\_read\_only\_addr <arg>
+.. program:: clang
+
+.. program:: clang2
+.. option:: -segs\_read\_write\_addr <arg>
+.. program:: clang
+
+.. option:: -serialize-diagnostics <arg>, --serialize-diagnostics <arg>
+
+Serialize compiler diagnostics to a file
+
+.. option:: -shared, --shared
+
+.. option:: -shared-libasan
+
+.. option:: -shared-libgcc
+
+.. option:: -single\_module
+
+.. option:: -specs=<arg>, --specs=<arg>
+
+.. option:: -static, --static
+
+.. option:: -static-libgcc
+
+.. option:: -static-libstdc++
+
+.. option:: -std-default=<arg>
+
+.. option:: -stdlib=<arg>, --stdlib=<arg>, --stdlib <arg>
+
+C++ standard library to use
+
+.. option:: -sub\_library<arg>
+
+.. program:: clang1
+.. option:: -sub\_umbrella<arg>
+.. program:: clang
+
+.. option:: --sysroot=<arg>, --sysroot <arg>
+
+.. option:: --target-help
+
+.. option:: --target=<arg>, -target <arg>
+
+Generate code for the given target
+
+.. option:: -time
+
+Time individual commands
+
+.. option:: -traditional, --traditional
+
+.. option:: -traditional-cpp, --traditional-cpp
+
+Enable some traditional CPP emulation
+
+.. option:: -twolevel\_namespace
+
+.. program:: clang1
+.. option:: -twolevel\_namespace\_hints
+.. program:: clang
+
+.. option:: -umbrella <arg>
+
+.. option:: -unexported\_symbols\_list <arg>
+
+.. option:: -v, --verbose
+
+Show commands to run and use verbose output
+
+.. option:: --verify-debug-info
+
+Verify the binary representation of debug output
+
+.. option:: --version
+
+.. option:: -w, --no-warnings
+
+Suppress all warnings
+
+.. option:: -weak-l<arg>
+
+.. option:: -weak\_framework <arg>
+
+.. program:: clang1
+.. option:: -weak\_library <arg>
+.. program:: clang
+
+.. program:: clang2
+.. option:: -weak\_reference\_mismatches <arg>
+.. program:: clang
+
+.. option:: -whatsloaded
+
+.. option:: -whyload
+
+.. option:: -working-directory<arg>, -working-directory=<arg>
+
+Resolve file paths relative to the specified directory
+
+.. option:: -x<language>, --language <arg>, --language=<arg>
+
+Treat subsequent input files as having type <language>
+
+.. option:: -y<arg>
+
+Actions
+=======
+The action to perform on the input.
+
+.. option:: -E, --preprocess
+
+Only run the preprocessor
+
+.. option:: -S, --assemble
+
+Only run preprocess and compilation steps
+
+.. option:: -c, --compile
+
+Only run preprocess, compile, and assemble steps
+
+.. option:: -emit-llvm
+
+Use the LLVM representation for assembler and object files
+
+.. option:: -fsyntax-only
+
+.. option:: -module-file-info
+
+Provide information about a particular module file
+
+.. option:: --precompile
+
+Only precompile the input
+
+.. option:: -rewrite-objc
+
+Rewrite Objective-C source to C++
+
+.. option:: -verify-pch
+
+Load and verify that a pre-compiled header file is not stale
+
+Compilation flags
+=================
+
+Flags controlling the behavior of Clang during compilation. These flags have
+no effect during actions that do not perform compilation.
+
+.. option:: -Xassembler <arg>
+
+Pass <arg> to the assembler
+
+.. option:: -Xclang <arg>
+
+Pass <arg> to the clang compiler
+
+.. option:: -fcomment-block-commands=<arg>,<arg2>...
+
+Treat each comma separated argument in <arg> as a documentation comment block command
+
+.. option:: -fdeclspec, -fno-declspec
+
+Allow \_\_declspec as a keyword
+
+.. option:: -fdepfile-entry=<arg>
+
+.. option:: -fdiagnostics-fixit-info, -fno-diagnostics-fixit-info
+
+.. option:: -fdiagnostics-format=<arg>
+
+.. option:: -fdiagnostics-parseable-fixits
+
+Print fix-its in machine parseable form
+
+.. option:: -fdiagnostics-print-source-range-info
+
+Print source range spans in numeric form
+
+.. option:: -fdiagnostics-show-category=<arg>
+
+.. option:: -fexperimental-new-pass-manager, -fno-experimental-new-pass-manager
+
+Enables an experimental new pass manager in LLVM.
+
+.. option:: -finline-functions, -fno-inline-functions
+
+Inline suitable functions
+
+.. option:: -finline-hint-functions
+
+Inline functions which are (explicitly or implicitly) marked inline
+
+.. option:: -fno-crash-diagnostics
+
+Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash
+
+.. option:: -fno-sanitize-blacklist
+
+Don't use blacklist file for sanitizers
+
+.. option:: -fparse-all-comments
+
+.. option:: -fsanitize-address-field-padding=<arg>
+
+Level of field padding for AddressSanitizer
+
+.. option:: -fsanitize-address-use-after-scope, -fno-sanitize-address-use-after-scope
+
+Enable use-after-scope detection in AddressSanitizer
+
+.. option:: -fsanitize-blacklist=<arg>
+
+Path to blacklist file for sanitizers
+
+.. option:: -fsanitize-cfi-cross-dso, -fno-sanitize-cfi-cross-dso
+
+Enable control flow integrity (CFI) checks for cross-DSO calls.
+
+.. option:: -fsanitize-coverage=<arg1>,<arg2>..., -fno-sanitize-coverage=<arg1>,<arg2>...
+
+Specify the type of coverage instrumentation for Sanitizers
+
+.. option:: -fsanitize-link-c++-runtime
+
+.. option:: -fsanitize-memory-track-origins, -fno-sanitize-memory-track-origins
+
+Enable origins tracking in MemorySanitizer
+
+.. program:: clang1
+.. option:: -fsanitize-memory-track-origins=<arg>
+.. program:: clang
+
+Enable origins tracking in MemorySanitizer
+
+.. option:: -fsanitize-memory-use-after-dtor
+
+Enable use-after-destroy detection in MemorySanitizer
+
+.. option:: -fsanitize-recover, -fno-sanitize-recover
+
+.. program:: clang1
+.. option:: -fsanitize-recover=<arg1>,<arg2>..., -fno-sanitize-recover=<arg1>,<arg2>...
+.. program:: clang
+
+Enable recovery for specified sanitizers
+
+.. option:: -fsanitize-stats, -fno-sanitize-stats
+
+Enable sanitizer statistics gathering.
+
+.. option:: -fsanitize-thread-atomics, -fno-sanitize-thread-atomics
+
+Enable atomic operations instrumentation in ThreadSanitizer (default)
+
+.. option:: -fsanitize-thread-func-entry-exit, -fno-sanitize-thread-func-entry-exit
+
+Enable function entry/exit instrumentation in ThreadSanitizer (default)
+
+.. option:: -fsanitize-thread-memory-access, -fno-sanitize-thread-memory-access
+
+Enable memory access instrumentation in ThreadSanitizer (default)
+
+.. option:: -fsanitize-trap=<arg1>,<arg2>..., -fno-sanitize-trap=<arg1>,<arg2>...
+
+Enable trapping for specified sanitizers
+
+.. option:: -fsanitize-undefined-strip-path-components=<number>
+
+Strip (or keep only, if negative) a given number of path components when emitting check metadata.
+
+.. option:: -fsanitize-undefined-trap-on-error, -fno-sanitize-undefined-trap-on-error
+
+.. option:: -fsanitize=<check>,<arg2>..., -fno-sanitize=<arg1>,<arg2>...
+
+Turn on runtime checks for various forms of undefined or suspicious behavior. See user manual for available checks
+
+.. option:: --param <arg>, --param=<arg>
+
+.. option:: -std=<arg>, --std=<arg>, --std <arg>
+
+Language standard to compile for
+
+Preprocessor flags
+~~~~~~~~~~~~~~~~~~
+
+Flags controlling the behavior of the Clang preprocessor.
+
+.. option:: -C, --comments
+
+Include comments in preprocessed output
+
+.. option:: -CC, --comments-in-macros
+
+Include comments from within macros in preprocessed output
+
+.. option:: -D<macro>=<value>, --define-macro <arg>, --define-macro=<arg>
+
+Define <macro> to <value> (or 1 if <value> omitted)
+
+.. option:: -H, --trace-includes
+
+Show header includes and nesting depth
+
+.. option:: -P, --no-line-commands
+
+Disable linemarker output in -E mode
+
+.. option:: -U<macro>, --undefine-macro <arg>, --undefine-macro=<arg>
+
+Undefine macro <macro>
+
+.. option:: -Wp,<arg>,<arg2>...
+
+Pass the comma separated arguments in <arg> to the preprocessor
+
+.. option:: -Xpreprocessor <arg>
+
+Pass <arg> to the preprocessor
+
+Include path management
+-----------------------
+
+Flags controlling how ``#include``\s are resolved to files.
+
+.. option:: -I<dir>, --include-directory <arg>, --include-directory=<arg>
+
+Add directory to include search path
+
+.. option:: -I-, --include-barrier
+
+Restrict all prior -I flags to double-quoted inclusion and remove current directory from include path
+
+.. option:: --cuda-path=<arg>
+
+CUDA installation path
+
+.. option:: -cxx-isystem<directory>
+
+Add directory to the C++ SYSTEM include search path
+
+.. option:: -fbuild-session-file=<file>
+
+Use the last modification time of <file> as the build session timestamp
+
+.. option:: -fbuild-session-timestamp=<time since Epoch in seconds>
+
+Time when the current build session started
+
+.. option:: -fmodules-cache-path=<directory>
+
+Specify the module cache path
+
+.. option:: -fmodules-disable-diagnostic-validation
+
+Disable validation of the diagnostic options when loading the module
+
+.. option:: -fmodules-prune-after=<seconds>
+
+Specify the interval (in seconds) after which a module file will be considered unused
+
+.. option:: -fmodules-prune-interval=<seconds>
+
+Specify the interval (in seconds) between attempts to prune the module cache
+
+.. option:: -fmodules-user-build-path <directory>
+
+Specify the module user build path
+
+.. option:: -fmodules-validate-once-per-build-session
+
+Don't verify input files for the modules if the module has been successfully validated or loaded during this build session
+
+.. option:: -fmodules-validate-system-headers
+
+Validate the system headers that a module depends on when loading the module
+
+.. option:: -fprebuilt-module-path=<directory>
+
+Specify the prebuilt module path
+
+.. option:: -i<arg>
+
+.. option:: -idirafter<arg>, --include-directory-after <arg>, --include-directory-after=<arg>
+
+Add directory to AFTER include search path
+
+.. option:: -iframework<arg>
+
+Add directory to SYSTEM framework search path
+
+.. option:: -iframeworkwithsysroot<directory>
+
+Add directory to SYSTEM framework search path, absolute paths are relative to -isysroot
+
+.. option:: -imacros<file>, --imacros<file>, --imacros=<arg>
+
+Include macros from file before parsing
+
+.. option:: -include<file>, --include<file>, --include=<arg>
+
+Include file before parsing
+
+.. option:: -include-pch <file>
+
+Include precompiled header file
+
+.. option:: -iprefix<dir>, --include-prefix <arg>, --include-prefix=<arg>
+
+Set the -iwithprefix/-iwithprefixbefore prefix
+
+.. option:: -iquote<directory>
+
+Add directory to QUOTE include search path
+
+.. option:: -isysroot<dir>
+
+Set the system root directory (usually /)
+
+.. option:: -isystem<directory>
+
+Add directory to SYSTEM include search path
+
+.. option:: -isystem-after<directory>
+
+Add directory to end of the SYSTEM include search path
+
+.. option:: -ivfsoverlay<arg>
+
+Overlay the virtual filesystem described by file over the real file system
+
+.. option:: -iwithprefix<dir>, --include-with-prefix <arg>, --include-with-prefix-after <arg>, --include-with-prefix-after=<arg>, --include-with-prefix=<arg>
+
+Set directory to SYSTEM include search path with prefix
+
+.. option:: -iwithprefixbefore<dir>, --include-with-prefix-before <arg>, --include-with-prefix-before=<arg>
+
+Set directory to include search path with prefix
+
+.. option:: -iwithsysroot<directory>
+
+Add directory to SYSTEM include search path, absolute paths are relative to -isysroot
+
+.. option:: --ptxas-path=<arg>
+
+Path to ptxas (used for compiling CUDA code)
+
+.. option:: --system-header-prefix=<prefix>, --no-system-header-prefix=<prefix>, --system-header-prefix <arg>
+
+Treat all #include paths starting with <prefix> as including a system header.
+
+Dependency file generation
+--------------------------
+
+Flags controlling generation of a dependency file for ``make``-like build
+systems.
+
+.. option:: -M, --dependencies
+
+Like -MD, but also implies -E and writes to stdout by default
+
+.. option:: -MD, --write-dependencies
+
+Write a depfile containing user and system headers
+
+.. option:: -MF<file>
+
+Write depfile output from -MMD, -MD, -MM, or -M to <file>
+
+.. option:: -MG, --print-missing-file-dependencies
+
+Add missing headers to depfile
+
+.. option:: -MJ<arg>
+
+Write a compilation database entry per input
+
+.. option:: -MM, --user-dependencies
+
+Like -MMD, but also implies -E and writes to stdout by default
+
+.. option:: -MMD, --write-user-dependencies
+
+Write a depfile containing user headers
+
+.. option:: -MP
+
+Create phony target for each dependency (other than main file)
+
+.. option:: -MQ<arg>
+
+Specify name of main file output to quote in depfile
+
+.. option:: -MT<arg>
+
+Specify name of main file output in depfile
+
+.. option:: -MV
+
+Use NMake/Jom format for the depfile
+
+Dumping preprocessor state
+--------------------------
+
+Flags allowing the state of the preprocessor to be dumped in various ways.
+
+.. option:: -d
+
+.. program:: clang1
+.. option:: -d<arg>
+.. program:: clang
+
+.. option:: -dA
+
+.. option:: -dD
+
+Print macro definitions in -E mode in addition to normal output
+
+.. option:: -dI
+
+Print include directives in -E mode in addition to normal output
+
+.. option:: -dM
+
+Print macro definitions in -E mode instead of normal output
+
+Diagnostic flags
+~~~~~~~~~~~~~~~~
+
+Flags controlling which warnings, errors, and remarks Clang will generate.
+See the :doc:`full list of warning and remark flags <DiagnosticsReference>`.
+
+.. option:: -R<remark>
+
+Enable the specified remark
+
+.. option:: -Rpass-analysis=<arg>
+
+Report transformation analysis from optimization passes whose name matches the given POSIX regular expression
+
+.. option:: -Rpass-missed=<arg>
+
+Report missed transformations by optimization passes whose name matches the given POSIX regular expression
+
+.. option:: -Rpass=<arg>
+
+Report transformations performed by optimization passes whose name matches the given POSIX regular expression
+
+.. option:: -W<warning>, --extra-warnings, --warn-<arg>, --warn-=<arg>
+
+Enable the specified warning
+
+.. option:: -Wdeprecated, -Wno-deprecated
+
+Enable warnings for deprecated constructs and define \_\_DEPRECATED
+
+.. option:: -Wnonportable-cfstrings<arg>, -Wno-nonportable-cfstrings<arg>
+
+Target-independent compilation options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. option:: -Wframe-larger-than=<arg>
+
+.. option:: -fPIC, -fno-PIC
+
+.. option:: -fPIE, -fno-PIE
+
+.. option:: -faccess-control, -fno-access-control
+
+.. program:: clang1
+.. option:: -faligned-allocation, -faligned-new, -fno-aligned-allocation
+.. program:: clang
+
+Enable C++17 aligned allocation functions
+
+.. option:: -fallow-unsupported
+
+.. option:: -faltivec, -fno-altivec
+
+.. option:: -fansi-escape-codes
+
+Use ANSI escape codes for diagnostics
+
+.. option:: -fapple-kext, -findirect-virtual-calls, -fterminated-vtables
+
+Use Apple's kernel extensions ABI
+
+.. option:: -fapple-pragma-pack, -fno-apple-pragma-pack
+
+Enable Apple gcc-compatible #pragma pack handling
+
+.. option:: -fapplication-extension, -fno-application-extension
+
+Restrict code to those available for App Extensions
+
+.. option:: -fasm, -fno-asm
+
+.. option:: -fasm-blocks, -fno-asm-blocks
+
+.. option:: -fassociative-math, -fno-associative-math
+
+.. option:: -fassume-sane-operator-new, -fno-assume-sane-operator-new
+
+.. option:: -fast
+
+.. option:: -fastcp
+
+.. option:: -fastf
+
+.. option:: -fasynchronous-unwind-tables, -fno-asynchronous-unwind-tables
+
+.. option:: -fautolink, -fno-autolink
+
+.. option:: -fblocks, -fno-blocks
+
+Enable the 'blocks' language feature
+
+.. option:: -fbootclasspath=<arg>, --bootclasspath <arg>, --bootclasspath=<arg>
+
+.. option:: -fborland-extensions, -fno-borland-extensions
+
+Accept non-standard constructs supported by the Borland compiler
+
+.. option:: -fbracket-depth=<arg>
+
+.. option:: -fbuiltin, -fno-builtin
+
+.. option:: -fbuiltin-module-map
+
+Load the clang builtins module map file.
+
+.. option:: -fcaret-diagnostics, -fno-caret-diagnostics
+
+.. option:: -fclasspath=<arg>, --CLASSPATH <arg>, --CLASSPATH=<arg>, --classpath <arg>, --classpath=<arg>
+
+.. option:: -fcolor-diagnostics, -fno-color-diagnostics
+
+Use colors in diagnostics
+
+.. option:: -fcommon, -fno-common
+
+.. option:: -fcompile-resource=<arg>, --resource <arg>, --resource=<arg>
+
+.. option:: -fconstant-cfstrings, -fno-constant-cfstrings
+
+.. option:: -fconstant-string-class=<arg>
+
+.. option:: -fconstexpr-backtrace-limit=<arg>
+
+.. option:: -fconstexpr-depth=<arg>
+
+.. option:: -fconstexpr-steps=<arg>
+
+.. option:: -fcoroutines-ts, -fno-coroutines-ts
+
+Enable support for the C++ Coroutines TS
+
+.. option:: -fcoverage-mapping, -fno-coverage-mapping
+
+Generate coverage mapping to enable code coverage analysis
+
+.. option:: -fcreate-profile
+
+.. option:: -fcxx-exceptions, -fno-cxx-exceptions
+
+Enable C++ exceptions
+
+.. option:: -fcxx-modules, -fno-cxx-modules
+
+.. option:: -fdata-sections, -fno-data-sections
+
+Place each data in its own section (ELF Only)
+
+.. option:: -fdebug-info-for-profiling, -fno-debug-info-for-profiling
+
+Emit extra debug info to make sample profile more accurate.
+
+.. option:: -fdebug-macro, -fno-debug-macro
+
+Emit macro debug information
+
+.. option:: -fdebug-pass-arguments
+
+.. option:: -fdebug-pass-structure
+
+.. option:: -fdebug-prefix-map=<arg>
+
+remap file source paths in debug info
+
+.. option:: -fdebug-types-section, -fno-debug-types-section
+
+Place debug types in their own section (ELF Only)
+
+.. option:: -fdelayed-template-parsing, -fno-delayed-template-parsing
+
+Parse templated function definitions at the end of the translation unit
+
+.. option:: -fdenormal-fp-math=<arg>
+
+.. option:: -fdiagnostics-absolute-paths
+
+Print absolute paths in diagnostics
+
+.. option:: -fdiagnostics-color, -fno-diagnostics-color
+
+.. program:: clang1
+.. option:: -fdiagnostics-color=<arg>
+.. program:: clang
+
+.. option:: -fdiagnostics-show-hotness, -fno-diagnostics-show-hotness
+
+Enable profile hotness information in diagnostic line
+
+.. option:: -fdiagnostics-show-note-include-stack, -fno-diagnostics-show-note-include-stack
+
+Display include stacks for diagnostic notes
+
+.. option:: -fdiagnostics-show-option, -fno-diagnostics-show-option
+
+Print option name with mappable diagnostics
+
+.. option:: -fdiagnostics-show-template-tree
+
+Print a template comparison tree for differing templates
+
+.. option:: -fdollars-in-identifiers, -fno-dollars-in-identifiers
+
+Allow '$' in identifiers
+
+.. option:: -fdwarf-directory-asm, -fno-dwarf-directory-asm
+
+.. option:: -felide-constructors, -fno-elide-constructors
+
+.. option:: -feliminate-unused-debug-symbols, -fno-eliminate-unused-debug-symbols
+
+.. option:: -fembed-bitcode=<option>, -fembed-bitcode (equivalent to -fembed-bitcode=all), -fembed-bitcode-marker (equivalent to -fembed-bitcode=marker)
+
+Embed LLVM bitcode (option: off, all, bitcode, marker)
+
+.. option:: -femit-all-decls
+
+Emit all declarations, even if unused
+
+.. option:: -femulated-tls, -fno-emulated-tls
+
+Use emutls functions to access thread\_local variables
+
+.. option:: -fencoding=<arg>, --encoding <arg>, --encoding=<arg>
+
+.. option:: -ferror-limit=<arg>
+
+.. option:: -fexceptions, -fno-exceptions
+
+Enable support for exception handling
+
+.. option:: -fexec-charset=<arg>
+
+.. option:: -fextdirs=<arg>, --extdirs <arg>, --extdirs=<arg>
+
+.. option:: -ffast-math, -fno-fast-math
+
+Allow aggressive, lossy floating-point optimizations
+
+.. option:: -ffinite-math-only, -fno-finite-math-only
+
+.. option:: -ffor-scope, -fno-for-scope
+
+.. option:: -ffp-contract=<arg>
+
+Form fused FP ops (e.g. FMAs): fast (everywhere) \| on (according to FP\_CONTRACT pragma, default) \| off (never fuse)
+
+.. option:: -ffreestanding
+
+Assert that the compilation takes place in a freestanding environment
+
+.. option:: -ffunction-sections, -fno-function-sections
+
+Place each function in its own section (ELF Only)
+
+.. option:: -fgnu-inline-asm, -fno-gnu-inline-asm
+
+.. option:: -fgnu-keywords, -fno-gnu-keywords
+
+Allow GNU-extension keywords regardless of language standard
+
+.. option:: -fgnu-runtime
+
+Generate output compatible with the standard GNU Objective-C runtime
+
+.. option:: -fgnu89-inline, -fno-gnu89-inline
+
+Use the gnu89 inline semantics
+
+.. option:: -fhonor-infinities, -fhonor-infinites, -fno-honor-infinities
+
+.. option:: -fhonor-nans, -fno-honor-nans
+
+.. option:: -fhosted
+
+.. option:: -fimplicit-module-maps, -fmodule-maps, -fno-implicit-module-maps
+
+Implicitly search the file system for module map files.
+
+.. option:: -fimplicit-modules, -fno-implicit-modules
+
+.. option:: -finput-charset=<arg>
+
+.. option:: -finstrument-functions
+
+Generate calls to instrument function entry and exit
+
+.. option:: -fintegrated-as, -fno-integrated-as, -integrated-as
+
+Enable the integrated assembler
+
+.. option:: -fjump-tables, -fno-jump-tables
+
+.. option:: -flax-vector-conversions, -fno-lax-vector-conversions
+
+.. option:: -flimited-precision=<arg>
+
+.. option:: -flto, -fno-lto
+
+Enable LTO in 'full' mode
+
+.. option:: -flto-jobs=<arg>
+
+Controls the backend parallelism of -flto=thin (default of 0 means the number of threads will be derived from the number of CPUs detected)
+
+.. program:: clang1
+.. option:: -flto=<arg>
+.. program:: clang
+
+Set LTO mode to either 'full' or 'thin'
+
+.. option:: -fmacro-backtrace-limit=<arg>
+
+.. option:: -fmath-errno, -fno-math-errno
+
+Require math functions to indicate errors by setting errno
+
+.. option:: -fmax-type-align=<arg>
+
+Specify the maximum alignment to enforce on pointers lacking an explicit alignment
+
+.. option:: -fmerge-all-constants, -fno-merge-all-constants
+
+.. option:: -fmessage-length=<arg>
+
+.. option:: -fmodule-file-deps, -fno-module-file-deps
+
+.. option:: -fmodule-file=<file>
+
+Load this precompiled module file
+
+.. option:: -fmodule-map-file=<file>
+
+Load this module map file
+
+.. option:: -fmodule-name=<name>, -fmodule-implementation-of <arg>, -fmodule-name <arg>
+
+Specify the name of the module to build
+
+.. option:: -fmodules, -fno-modules
+
+Enable the 'modules' language feature
+
+.. option:: -fmodules-decluse, -fno-modules-decluse
+
+Require declaration of modules used within a module
+
+.. option:: -fmodules-ignore-macro=<arg>
+
+Ignore the definition of the given macro when building and loading modules
+
+.. option:: -fmodules-search-all, -fno-modules-search-all
+
+Search even non-imported modules to resolve references
+
+.. option:: -fmodules-strict-decluse
+
+Like -fmodules-decluse but requires all headers to be in modules
+
+.. option:: -fmodules-ts
+
+Enable support for the C++ Modules TS
+
+.. option:: -fms-compatibility, -fno-ms-compatibility
+
+Enable full Microsoft Visual C++ compatibility
+
+.. option:: -fms-compatibility-version=<arg>
+
+Dot-separated value representing the Microsoft compiler version number to report in \_MSC\_VER (0 = don't define it (default))
+
+.. option:: -fms-extensions, -fno-ms-extensions
+
+Accept some non-standard constructs supported by the Microsoft compiler
+
+.. option:: -fms-memptr-rep=<arg>
+
+.. option:: -fms-volatile<arg>
+
+.. option:: -fmsc-version=<arg>
+
+Microsoft compiler version number to report in \_MSC\_VER (0 = don't define it (default))
+
+.. option:: -fmudflap
+
+.. option:: -fmudflapth
+
+.. option:: -fnested-functions
+
+.. option:: -fnew-alignment=<align>, -fnew-alignment <arg>
+
+Specifies the largest alignment guaranteed by '::operator new(size\_t)'
+
+.. option:: -fnext-runtime
+
+.. option:: -fno-builtin-<arg>
+
+Disable implicit builtin knowledge of a specific function
+
+.. option:: -fno-elide-type
+
+Do not elide types when printing diagnostics
+
+.. option:: -fno-max-type-align
+
+.. option:: -fno-operator-names
+
+Do not treat C++ operator name keywords as synonyms for operators
+
+.. option:: -fno-strict-modules-decluse
+
+.. option:: -fno-working-directory
+
+.. option:: -fnoopenmp-use-tls
+
+.. option:: -fobjc-abi-version=<arg>
+
+.. option:: -fobjc-arc, -fno-objc-arc
+
+Synthesize retain and release calls for Objective-C pointers
+
+.. option:: -fobjc-arc-exceptions, -fno-objc-arc-exceptions
+
+Use EH-safe code when synthesizing retains and releases in -fobjc-arc
+
+.. option:: -fobjc-exceptions, -fno-objc-exceptions
+
+Enable Objective-C exceptions
+
+.. option:: -fobjc-infer-related-result-type, -fno-objc-infer-related-result-type
+
+.. option:: -fobjc-legacy-dispatch, -fno-objc-legacy-dispatch
+
+.. option:: -fobjc-link-runtime
+
+.. option:: -fobjc-nonfragile-abi, -fno-objc-nonfragile-abi
+
+.. option:: -fobjc-nonfragile-abi-version=<arg>
+
+.. option:: -fobjc-runtime=<arg>
+
+Specify the target Objective-C runtime kind and version
+
+.. option:: -fobjc-sender-dependent-dispatch
+
+.. option:: -fobjc-weak, -fno-objc-weak
+
+Enable ARC-style weak references in Objective-C
+
+.. option:: -fomit-frame-pointer, -fno-omit-frame-pointer
+
+.. option:: -fopenmp, -fno-openmp
+
+.. option:: -fopenmp-dump-offload-linker-script
+
+.. option:: -fopenmp-use-tls
+
+.. option:: -fopenmp-version=<arg>
+
+.. program:: clang1
+.. option:: -fopenmp=<arg>
+.. program:: clang
+
+.. option:: -foperator-arrow-depth=<arg>
+
+.. option:: -foptimization-record-file=<arg>
+
+Specify the file name of any generated YAML optimization record
+
+.. option:: -foptimize-sibling-calls, -fno-optimize-sibling-calls
+
+.. option:: -foutput-class-dir=<arg>, --output-class-directory <arg>, --output-class-directory=<arg>
+
+.. option:: -fpack-struct, -fno-pack-struct
+
+.. program:: clang1
+.. option:: -fpack-struct=<arg>
+.. program:: clang
+
+Specify the default maximum struct packing alignment
+
+.. option:: -fpascal-strings, -fno-pascal-strings, -mpascal-strings
+
+Recognize and construct Pascal-style string literals
+
+.. option:: -fpcc-struct-return
+
+Override the default ABI to return all structs on the stack
+
+.. option:: -fpch-preprocess
+
+.. option:: -fpic, -fno-pic
+
+.. option:: -fpie, -fno-pie
+
+.. option:: -fplugin=<dsopath>
+
+Load the named plugin (dynamic shared object)
+
+.. option:: -fpreserve-as-comments, -fno-preserve-as-comments
+
+.. option:: -fprofile-arcs, -fno-profile-arcs
+
+.. option:: -fprofile-dir=<arg>
+
+.. option:: -fprofile-generate, -fno-profile-generate
+
+Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM\_PROFILE\_FILE env var)
+
+.. program:: clang1
+.. option:: -fprofile-generate=<directory>
+.. program:: clang
+
+Generate instrumented code to collect execution counts into <directory>/default.profraw (overridden by LLVM\_PROFILE\_FILE env var)
+
+.. option:: -fprofile-instr-generate, -fno-profile-instr-generate
+
+Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM\_PROFILE\_FILE env var)
+
+.. program:: clang1
+.. option:: -fprofile-instr-generate=<file>
+.. program:: clang
+
+Generate instrumented code to collect execution counts into <file> (overridden by LLVM\_PROFILE\_FILE env var)
+
+.. option:: -fprofile-instr-use, -fno-profile-instr-use, -fprofile-use
+
+.. program:: clang1
+.. option:: -fprofile-instr-use=<arg>
+.. program:: clang
+
+Use instrumentation data for profile-guided optimization
+
+.. option:: -fprofile-sample-use, -fauto-profile, -fno-profile-sample-use
+
+.. program:: clang1
+.. option:: -fprofile-sample-use=<arg>, -fauto-profile=<arg>
+.. program:: clang
+
+Enable sample-based profile guided optimizations
+
+.. program:: clang1
+.. option:: -fprofile-use=<pathname>
+.. program:: clang
+
+Use instrumentation data for profile-guided optimization. If pathname is a directory, it reads from <pathname>/default.profdata. Otherwise, it reads from file <pathname>.
+
+.. option:: -freciprocal-math, -fno-reciprocal-math
+
+Allow division operations to be reassociated
+
+.. option:: -freg-struct-return
+
+Override the default ABI to return small structs in registers
+
+.. option:: -frelaxed-template-template-args, -fno-relaxed-template-template-args
+
+Enable C++17 relaxed template template argument matching
+
+.. option:: -freroll-loops, -fno-reroll-loops
+
+Turn on loop reroller
+
+.. option:: -fretain-comments-from-system-headers
+
+.. option:: -frewrite-includes, -fno-rewrite-includes
+
+.. option:: -frewrite-map-file <arg>
+
+.. program:: clang1
+.. option:: -frewrite-map-file=<arg>
+.. program:: clang
+
+.. option:: -fropi, -fno-ropi
+
+.. option:: -frtti, -fno-rtti
+
+.. option:: -frwpi, -fno-rwpi
+
+.. option:: -fsave-optimization-record, -fno-save-optimization-record
+
+Generate a YAML optimization record file
+
+.. option:: -fshort-enums, -fno-short-enums
+
+Allocate to an enum type only as many bytes as it needs for the declared range of possible values
+
+.. option:: -fshort-wchar, -fno-short-wchar
+
+Force wchar\_t to be a short unsigned int
+
+.. option:: -fshow-column, -fno-show-column
+
+.. option:: -fshow-overloads=<arg>
+
+Which overload candidates to show when overload resolution fails: best\|all; defaults to all
+
+.. option:: -fshow-source-location, -fno-show-source-location
+
+.. option:: -fsignaling-math, -fno-signaling-math
+
+.. option:: -fsigned-bitfields
+
+.. option:: -fsigned-char, -fno-signed-char, --signed-char
+
+.. option:: -fsigned-zeros, -fno-signed-zeros
+
+.. option:: -fsized-deallocation, -fno-sized-deallocation
+
+Enable C++14 sized global deallocation functions
+
+.. option:: -fsjlj-exceptions
+
+Use SjLj style exceptions
+
+.. option:: -fslp-vectorize, -fno-slp-vectorize, -ftree-slp-vectorize
+
+Enable the superword-level parallelism vectorization passes
+
+.. option:: -fslp-vectorize-aggressive, -fno-slp-vectorize-aggressive
+
+Enable the BB vectorization passes
+
+.. option:: -fspell-checking, -fno-spell-checking
+
+.. option:: -fspell-checking-limit=<arg>
+
+.. option:: -fsplit-dwarf-inlining, -fno-split-dwarf-inlining
+
+Place debug types in their own section (ELF Only)
+
+.. option:: -fsplit-stack
+
+.. option:: -fstack-protector, -fno-stack-protector
+
+Enable stack protectors for functions potentially vulnerable to stack smashing
+
+.. option:: -fstack-protector-all
+
+Force the usage of stack protectors for all functions
+
+.. option:: -fstack-protector-strong
+
+Use a strong heuristic to apply stack protectors to functions
+
+.. option:: -fstandalone-debug, -fno-limit-debug-info, -fno-standalone-debug
+
+Emit full debug info for all types used by the program
+
+.. option:: -fstrict-aliasing, -fno-strict-aliasing
+
+.. option:: -fstrict-enums, -fno-strict-enums
+
+Enable optimizations based on the strict definition of an enum's value range
+
+.. option:: -fstrict-overflow, -fno-strict-overflow
+
+.. option:: -fstrict-return, -fno-strict-return
+
+Always treat control flow paths that fall off the end of a non-void function as unreachable
+
+.. option:: -fstrict-vtable-pointers, -fno-strict-vtable-pointers
+
+Enable optimizations based on the strict rules for overwriting polymorphic C++ objects
+
+.. option:: -fstruct-path-tbaa, -fno-struct-path-tbaa
+
+.. option:: -ftabstop=<arg>
+
+.. option:: -ftemplate-backtrace-limit=<arg>
+
+.. option:: -ftemplate-depth-<arg>
+
+.. option:: -ftemplate-depth=<arg>
+
+.. option:: -ftest-coverage
+
+.. option:: -fthinlto-index=<arg>
+
+Perform ThinLTO importing using provided function summary index
+
+.. option:: -fthreadsafe-statics, -fno-threadsafe-statics
+
+.. option:: -ftime-report
+
+.. option:: -ftls-model=<arg>
+
+.. option:: -ftrap-function=<arg>
+
+Issue call to specified function rather than a trap instruction
+
+.. option:: -ftrapping-math, -fno-trapping-math
+
+.. option:: -ftrapv
+
+Trap on integer overflow
+
+.. option:: -ftrapv-handler <arg>
+
+.. program:: clang1
+.. option:: -ftrapv-handler=<function name>
+.. program:: clang
+
+Specify the function to be called on overflow
+
+.. option:: -ftrigraphs, -fno-trigraphs, -trigraphs, --trigraphs
+
+Process trigraph sequences
+
+.. option:: -funique-section-names, -fno-unique-section-names
+
+Use unique names for text and data sections (ELF Only)
+
+.. option:: -funit-at-a-time, -fno-unit-at-a-time
+
+.. option:: -funroll-loops, -fno-unroll-loops
+
+Turn on loop unroller
+
+.. option:: -funsafe-math-optimizations, -fno-unsafe-math-optimizations
+
+.. option:: -funsigned-bitfields
+
+.. option:: -funsigned-char, -fno-unsigned-char, --unsigned-char
+
+.. option:: -funwind-tables, -fno-unwind-tables
+
+.. option:: -fuse-cxa-atexit, -fno-use-cxa-atexit
+
+.. option:: -fuse-init-array, -fno-use-init-array
+
+Use .init\_array instead of .ctors
+
+.. option:: -fuse-ld=<arg>
+
+.. option:: -fuse-line-directives, -fno-use-line-directives
+
+.. option:: -fveclib=<arg>
+
+Use the given vector functions library
+
+.. option:: -fvectorize, -fno-vectorize, -ftree-vectorize
+
+Enable the loop vectorization passes
+
+.. option:: -fverbose-asm, -fno-verbose-asm
+
+.. option:: -fvisibility-inlines-hidden
+
+Give inline C++ member functions default visibility by default
+
+.. option:: -fvisibility-ms-compat
+
+Give global types 'default' visibility and global functions and variables 'hidden' visibility by default
+
+.. option:: -fvisibility=<arg>
+
+Set the default symbol visibility for all global declarations
+
+.. option:: -fwhole-program-vtables, -fno-whole-program-vtables
+
+Enables whole-program vtable optimization. Requires -flto
+
+.. option:: -fwrapv, -fno-wrapv
+
+Treat signed integer overflow as two's complement
+
+.. option:: -fwritable-strings
+
+Store string literals as writable data
+
+.. option:: -fxray-always-instrument=<arg>
+
+Filename defining the whitelist for imbuing the 'always instrument' XRay attribute.
+
+.. option:: -fxray-instruction-threshold<arg>
+
+.. program:: clang1
+.. option:: -fxray-instruction-threshold=<arg>
+.. program:: clang
+
+Sets the minimum function size to instrument with XRay
+
+.. option:: -fxray-instrument, -fno-xray-instrument
+
+Generate XRay instrumentation sleds on function entry and exit
+
+.. option:: -fxray-never-instrument=<arg>
+
+Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.
+
+.. option:: -fzero-initialized-in-bss, -fno-zero-initialized-in-bss
+
+.. option:: -fzvector, -fno-zvector, -mzvector
+
+Enable System z vector language extension
+
+.. option:: -pedantic, --pedantic, -no-pedantic, --no-pedantic
+
+.. option:: -pedantic-errors, --pedantic-errors
+
+OpenCL flags
+------------
+.. option:: -cl-denorms-are-zero
+
+OpenCL only. Allow denormals to be flushed to zero.
+
+.. option:: -cl-fast-relaxed-math
+
+OpenCL only. Sets -cl-finite-math-only and -cl-unsafe-math-optimizations, and defines \_\_FAST\_RELAXED\_MATH\_\_.
+
+.. option:: -cl-finite-math-only
+
+OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.
+
+.. option:: -cl-fp32-correctly-rounded-divide-sqrt
+
+OpenCL only. Specify that single precision floating-point divide and sqrt used in the program source are correctly rounded.
+
+.. option:: -cl-kernel-arg-info
+
+OpenCL only. Generate kernel argument metadata.
+
+.. option:: -cl-mad-enable
+
+OpenCL only. Allow use of less precise MAD computations in the generated binary.
+
+.. option:: -cl-no-signed-zeros
+
+OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.
+
+.. option:: -cl-opt-disable
+
+OpenCL only. This option disables all optimizations. By default optimizations are enabled.
+
+.. option:: -cl-single-precision-constant
+
+OpenCL only. Treat double precision floating-point constant as single precision constant.
+
+.. option:: -cl-std=<arg>
+
+OpenCL language standard to compile for.
+
+.. option:: -cl-strict-aliasing
+
+OpenCL only. This option is added for compatibility with OpenCL 1.0.
+
+.. option:: -cl-unsafe-math-optimizations
+
+OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable.
+
+Target-dependent compilation options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. option:: -G<size>, -G=<arg>, -msmall-data-threshold=<arg>
+
+Put objects of at most <size> bytes into small data section (MIPS / Hexagon)
+
+.. option:: -m16
+
+.. option:: -m32
+
+.. option:: -m64
+
+.. option:: -mabi=<arg>
+
+.. option:: -mabicalls, -mno-abicalls
+
+Enable SVR4-style position-independent code (Mips only)
+
+.. option:: -malign-double
+
+Align doubles to two words in structs (x86 only)
+
+.. option:: -march=<arg>
+
+.. option:: -masm=<arg>
+
+.. option:: -mbackchain, -mno-backchain
+
+Link stack frames through backchain on System Z
+
+.. option:: -mcheck-zero-division, -mno-check-zero-division
+
+.. option:: -mcmodel=<arg>
+
+.. option:: -mcompact-branches=<arg>
+
+.. option:: -mconsole<arg>
+
+.. option:: -mcpu=<arg>, -mv4 (equivalent to -mcpu=hexagonv4), -mv5 (equivalent to -mcpu=hexagonv5), -mv55 (equivalent to -mcpu=hexagonv55), -mv60 (equivalent to -mcpu=hexagonv60), -mv62 (equivalent to -mcpu=hexagonv62)
+
+.. option:: -mdll<arg>
+
+.. option:: -mdouble-float
+
+.. option:: -mdsp, -mno-dsp
+
+.. option:: -mdspr2, -mno-dspr2
+
+.. option:: -mdynamic-no-pic<arg>
+
+.. option:: -meabi <arg>
+
+Set EABI type, e.g. 4, 5 or gnu (default depends on triple)
+
+.. option:: -mfentry
+
+Insert calls to fentry at function entry (x86 only)
+
+.. option:: -mfloat-abi=<arg>
+
+.. option:: -mfp32
+
+Use 32-bit floating point registers (MIPS only)
+
+.. option:: -mfp64
+
+Use 64-bit floating point registers (MIPS only)
+
+.. option:: -mfpmath=<arg>
+
+.. option:: -mfpu=<arg>
+
+.. option:: -mglobal-merge, -mno-global-merge
+
+Enable merging of globals
+
+.. option:: -mhard-float
+
+.. option:: -mhwdiv=<arg>, --mhwdiv <arg>, --mhwdiv=<arg>
+
+.. option:: -miamcu, -mno-iamcu
+
+Use Intel MCU ABI
+
+.. option:: -mimplicit-float, -mno-implicit-float
+
+.. option:: -mimplicit-it=<arg>
+
+.. option:: -mincremental-linker-compatible, -mno-incremental-linker-compatible
+
+(integrated-as) Emit an object file which can be used with an incremental linker
+
+.. option:: -miphoneos-version-min=<arg>, -mios-version-min=<arg>
+
+.. option:: -mips16
+
+.. option:: -mkernel
+
+.. option:: -mldc1-sdc1, -mno-ldc1-sdc1
+
+.. option:: -mlong-calls, -mno-long-calls
+
+Generate branches with extended addressability, usually via indirect jumps.
+
+.. option:: -mmacosx-version-min=<arg>
+
+Set Mac OS X deployment target
+
+.. option:: -mmicromips, -mno-micromips
+
+.. option:: -mms-bitfields, -mno-ms-bitfields
+
+Set the default structure layout to be compatible with the Microsoft compiler standard
+
+.. option:: -mmsa, -mno-msa
+
+Enable MSA ASE (MIPS only)
+
+.. option:: -mnan=<arg>
+
+.. option:: -mno-mips16
+
+.. option:: -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer
+
+Omit frame pointer setup for leaf functions
+
+.. option:: -moslib=<arg>
+
+.. option:: -mpie-copy-relocations, -mno-pie-copy-relocations
+
+Use copy relocations support for PIE builds
+
+.. option:: -mqdsp6-compat
+
+Enable hexagon-qdsp6 backward compatibility
+
+.. option:: -mrecip
+
+.. program:: clang1
+.. option:: -mrecip=<arg1>,<arg2>...
+.. program:: clang
+
+.. option:: -mred-zone, -mno-red-zone
+
+.. option:: -mregparm=<arg>
+
+.. option:: -mrelax-all, -mno-relax-all
+
+(integrated-as) Relax all machine instructions
+
+.. option:: -mrtd, -mno-rtd
+
+Make StdCall calling convention the default
+
+.. option:: -msingle-float
+
+.. option:: -msoft-float, -mno-soft-float
+
+Use software floating point
+
+.. option:: -mstack-alignment=<arg>
+
+Set the stack alignment
+
+.. option:: -mstack-probe-size=<arg>
+
+Set the stack probe size
+
+.. option:: -mstackrealign, -mno-stackrealign
+
+Force realign the stack at entry to every function
+
+.. option:: -mthread-model <arg>
+
+The thread model to use, e.g. posix, single (posix by default)
+
+.. option:: -mthreads<arg>
+
+.. option:: -mthumb, -mno-thumb
+
+.. option:: -mtune=<arg>
+
+.. option:: -mtvos-version-min=<arg>, -mappletvos-version-min=<arg>
+
+.. option:: -municode<arg>
+
+.. option:: -mvx, -mno-vx
+
+.. option:: -mwarn-nonportable-cfstrings, -mno-warn-nonportable-cfstrings
+
+.. option:: -mwatchos-version-min=<arg>
+
+.. option:: -mwindows<arg>
+
+.. option:: -mx32
+
+.. option:: -mxgot, -mno-xgot
+
+AARCH64
+-------
+.. option:: -ffixed-x18
+
+Reserve the x18 register (AArch64 only)
+
+.. option:: -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769
+
+Workaround Cortex-A53 erratum 835769 (AArch64 only)
+
+.. option:: -mgeneral-regs-only
+
+Generate code which only uses the general purpose registers (AArch64 only)
+
+AMDGPU
+------
+ARM
+---
+.. option:: -ffixed-r9
+
+Reserve the r9 register (ARM only)
+
+.. option:: -mcrc
+
+Allow use of CRC instructions (ARM only)
+
+.. option:: -mexecute-only, -mno-execute-only, -mpure-code
+
+Disallow generation of data access to code sections (ARM only)
+
+.. option:: -mno-movt
+
+Disallow use of movt/movw pairs (ARM only)
+
+.. option:: -mno-neg-immediates
+
+Disallow converting instructions with negative immediates to their negation or inversion.
+
+.. option:: -mnocrc
+
+Disallow use of CRC instructions (ARM only)
+
+.. option:: -mrestrict-it, -mno-restrict-it
+
+Disallow generation of deprecated IT blocks for ARMv8. It is on by default for ARMv8 Thumb mode.
+
+.. option:: -munaligned-access, -mno-unaligned-access
+
+Allow memory accesses to be unaligned (AArch32/AArch64 only)
+
+Hexagon
+-------
+.. option:: -mhvx, -mno-hvx
+
+Enable Hexagon Vector eXtensions
+
+.. option:: -mhvx-double, -mno-hvx-double
+
+Enable Hexagon Double Vector eXtensions
+
+.. option:: -mieee-rnd-near
+
+PowerPC
+-------
+.. option:: -maltivec, -mno-altivec
+
+.. option:: -mcmpb, -mno-cmpb
+
+.. option:: -mcrbits, -mno-crbits
+
+.. option:: -mcrypto, -mno-crypto
+
+.. option:: -mdirect-move, -mno-direct-move
+
+.. option:: -mfloat128, -mno-float128
+
+.. option:: -mfprnd, -mno-fprnd
+
+.. option:: -mhtm, -mno-htm
+
+.. option:: -minvariant-function-descriptors, -mno-invariant-function-descriptors
+
+.. option:: -misel, -mno-isel
+
+.. option:: -mlongcall, -mno-longcall
+
+.. option:: -mmfocrf, -mmfcrf, -mno-mfocrf
+
+.. option:: -mpopcntd, -mno-popcntd
+
+.. option:: -mpower8-vector, -mno-power8-vector
+
+.. option:: -mpower9-vector, -mno-power9-vector
+
+.. option:: -mqpx, -mno-qpx
+
+.. option:: -mvsx, -mno-vsx
+
+WebAssembly
+-----------
+.. option:: -msimd128, -mno-simd128
+
+X86
+---
+.. option:: -m3dnow, -mno-3dnow
+
+.. option:: -m3dnowa, -mno-3dnowa
+
+.. option:: -madx, -mno-adx
+
+.. option:: -maes, -mno-aes
+
+.. option:: -mavx, -mno-avx
+
+.. option:: -mavx2, -mno-avx2
+
+.. option:: -mavx512bw, -mno-avx512bw
+
+.. option:: -mavx512cd, -mno-avx512cd
+
+.. option:: -mavx512dq, -mno-avx512dq
+
+.. option:: -mavx512er, -mno-avx512er
+
+.. option:: -mavx512f, -mno-avx512f
+
+.. option:: -mavx512ifma, -mno-avx512ifma
+
+.. option:: -mavx512pf, -mno-avx512pf
+
+.. option:: -mavx512vbmi, -mno-avx512vbmi
+
+.. option:: -mavx512vl, -mno-avx512vl
+
+.. option:: -mbmi, -mno-bmi
+
+.. option:: -mbmi2, -mno-bmi2
+
+.. option:: -mclflushopt, -mno-clflushopt
+
+.. option:: -mclwb, -mno-clwb
+
+.. option:: -mclzero, -mno-clzero
+
+.. option:: -mcx16, -mno-cx16
+
+.. option:: -mf16c, -mno-f16c
+
+.. option:: -mfma, -mno-fma
+
+.. option:: -mfma4, -mno-fma4
+
+.. option:: -mfsgsbase, -mno-fsgsbase
+
+.. option:: -mfxsr, -mno-fxsr
+
+.. option:: -mlzcnt, -mno-lzcnt
+
+.. option:: -mmmx, -mno-mmx
+
+.. option:: -mmovbe, -mno-movbe
+
+.. option:: -mmpx, -mno-mpx
+
+.. option:: -mmwaitx, -mno-mwaitx
+
+.. option:: -mpclmul, -mno-pclmul
+
+.. option:: -mpku, -mno-pku
+
+.. option:: -mpopcnt, -mno-popcnt
+
+.. option:: -mprefetchwt1, -mno-prefetchwt1
+
+.. option:: -mprfchw, -mno-prfchw
+
+.. option:: -mrdrnd, -mno-rdrnd
+
+.. option:: -mrdseed, -mno-rdseed
+
+.. option:: -mrtm, -mno-rtm
+
+.. option:: -msgx, -mno-sgx
+
+.. option:: -msha, -mno-sha
+
+.. option:: -msse, -mno-sse
+
+.. option:: -msse2, -mno-sse2
+
+.. option:: -msse3, -mno-sse3
+
+.. option:: -msse4.1, -mno-sse4.1
+
+.. program:: clang1
+.. option:: -msse4.2, -mno-sse4.2, -msse4
+.. program:: clang
+
+.. option:: -msse4a, -mno-sse4a
+
+.. option:: -mssse3, -mno-ssse3
+
+.. option:: -mtbm, -mno-tbm
+
+.. option:: -mx87, -m80387, -mno-x87
+
+.. option:: -mxop, -mno-xop
+
+.. option:: -mxsave, -mno-xsave
+
+.. option:: -mxsavec, -mno-xsavec
+
+.. option:: -mxsaveopt, -mno-xsaveopt
+
+.. option:: -mxsaves, -mno-xsaves
+
+Optimization level
+~~~~~~~~~~~~~~~~~~
+
+Flags controlling how much optimization should be performed.
+
+.. option:: -O<arg>, -O (equivalent to -O2), --optimize, --optimize=<arg>
+
+.. option:: -Ofast<arg>
+
+Debug information generation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Flags controlling how much and what kind of debug information should be
+generated.
+
+Kind and level of debug information
+-----------------------------------
+.. option:: -g, --debug, --debug=<arg>
+
+Generate source-level debug information
+
+.. option:: -gdwarf-2
+
+Generate source-level debug information with dwarf version 2
+
+.. option:: -gdwarf-3
+
+Generate source-level debug information with dwarf version 3
+
+.. option:: -gdwarf-4, -gdwarf
+
+Generate source-level debug information with dwarf version 4
+
+.. option:: -gdwarf-5
+
+Generate source-level debug information with dwarf version 5
+
+.. option:: -gfull
+
+.. option:: -gused
+
+Debug level
+___________
+.. option:: -g0
+
+.. option:: -g2
+
+.. option:: -g3
+
+.. option:: -ggdb0
+
+.. option:: -ggdb1
+
+.. option:: -ggdb2
+
+.. option:: -ggdb3
+
+.. option:: -gline-tables-only, -g1, -gmlt
+
+Emit debug line number tables only
+
+.. option:: -gmodules
+
+Generate debug info with external references to clang modules or precompiled headers
+
+Debugger to tune debug information for
+______________________________________
+.. option:: -ggdb
+
+.. option:: -glldb
+
+.. option:: -gsce
+
+Debug information flags
+-----------------------
+.. option:: -gcolumn-info, -gno-column-info
+
+.. option:: -gdwarf-aranges
+
+.. option:: -ggnu-pubnames
+
+.. option:: -grecord-gcc-switches, -gno-record-gcc-switches
+
+.. option:: -gsplit-dwarf
+
+.. option:: -gstrict-dwarf, -gno-strict-dwarf
+
+Static analyzer flags
+=====================
+
+Flags controlling the behavior of the Clang Static Analyzer.
+
+.. option:: -Xanalyzer <arg>
+
+Pass <arg> to the static analyzer
+
+Fortran compilation flags
+=========================
+
+Flags that will be passed onto the ``gfortran`` compiler when Clang is given
+a Fortran input.
+
+.. option:: -A<arg>, --assert <arg>, --assert=<arg>
+
+.. option:: -A-<arg>
+
+.. option:: -J<arg>
+
+.. option:: -cpp
+
+.. option:: -faggressive-function-elimination, -fno-aggressive-function-elimination
+
+.. option:: -falign-commons, -fno-align-commons
+
+.. option:: -fall-intrinsics, -fno-all-intrinsics
+
+.. option:: -fautomatic, -fno-automatic
+
+.. option:: -fbackslash, -fno-backslash
+
+.. option:: -fbacktrace, -fno-backtrace
+
+.. option:: -fblas-matmul-limit=<arg>
+
+.. option:: -fbounds-check, -fno-bounds-check
+
+.. option:: -fcheck-array-temporaries, -fno-check-array-temporaries
+
+.. option:: -fcheck=<arg>
+
+.. option:: -fcoarray=<arg>
+
+.. option:: -fconvert=<arg>
+
+.. option:: -fcray-pointer, -fno-cray-pointer
+
+.. option:: -fd-lines-as-code, -fno-d-lines-as-code
+
+.. option:: -fd-lines-as-comments, -fno-d-lines-as-comments
+
+.. option:: -fdefault-double-8, -fno-default-double-8
+
+.. option:: -fdefault-integer-8, -fno-default-integer-8
+
+.. option:: -fdefault-real-8, -fno-default-real-8
+
+.. option:: -fdollar-ok, -fno-dollar-ok
+
+.. option:: -fdump-fortran-optimized, -fno-dump-fortran-optimized
+
+.. option:: -fdump-fortran-original, -fno-dump-fortran-original
+
+.. option:: -fdump-parse-tree, -fno-dump-parse-tree
+
+.. option:: -fexternal-blas, -fno-external-blas
+
+.. option:: -ff2c, -fno-f2c
+
+.. option:: -ffixed-form, -fno-fixed-form
+
+.. option:: -ffixed-line-length-<arg>
+
+.. option:: -ffpe-trap=<arg>
+
+.. option:: -ffree-form, -fno-free-form
+
+.. option:: -ffree-line-length-<arg>
+
+.. option:: -ffrontend-optimize, -fno-frontend-optimize
+
+.. option:: -fimplicit-none, -fno-implicit-none
+
+.. option:: -finit-character=<arg>
+
+.. option:: -finit-integer=<arg>
+
+.. option:: -finit-local-zero, -fno-init-local-zero
+
+.. option:: -finit-logical=<arg>
+
+.. option:: -finit-real=<arg>
+
+.. option:: -finteger-4-integer-8, -fno-integer-4-integer-8
+
+.. option:: -fintrinsic-modules-path, -fno-intrinsic-modules-path
+
+.. option:: -fmax-array-constructor=<arg>
+
+.. option:: -fmax-errors=<arg>
+
+.. option:: -fmax-identifier-length, -fno-max-identifier-length
+
+.. option:: -fmax-stack-var-size=<arg>
+
+.. option:: -fmax-subrecord-length=<arg>
+
+.. option:: -fmodule-private, -fno-module-private
+
+.. option:: -fpack-derived, -fno-pack-derived
+
+.. option:: -fprotect-parens, -fno-protect-parens
+
+.. option:: -frange-check, -fno-range-check
+
+.. option:: -freal-4-real-10, -fno-real-4-real-10
+
+.. option:: -freal-4-real-16, -fno-real-4-real-16
+
+.. option:: -freal-4-real-8, -fno-real-4-real-8
+
+.. option:: -freal-8-real-10, -fno-real-8-real-10
+
+.. option:: -freal-8-real-16, -fno-real-8-real-16
+
+.. option:: -freal-8-real-4, -fno-real-8-real-4
+
+.. option:: -frealloc-lhs, -fno-realloc-lhs
+
+.. option:: -frecord-marker=<arg>
+
+.. option:: -frecursive, -fno-recursive
+
+.. option:: -frepack-arrays, -fno-repack-arrays
+
+.. option:: -fsecond-underscore, -fno-second-underscore
+
+.. option:: -fsign-zero, -fno-sign-zero
+
+.. option:: -fstack-arrays, -fno-stack-arrays
+
+.. option:: -funderscoring, -fno-underscoring
+
+.. option:: -fwhole-file, -fno-whole-file
+
+.. option:: -nocpp
+
+.. option:: -static-libgfortran
+
+Linker flags
+============
+Flags that are passed on to the linker
+
+.. option:: -L<dir>, --library-directory <arg>, --library-directory=<arg>
+
+Add directory to library search path
+
+.. option:: -Mach
+
+.. option:: -T<script>
+
+Specify <script> as linker script
+
+.. option:: -Tbss<addr>
+
+Set starting address of BSS to <addr>
+
+.. option:: -Tdata<addr>
+
+Set starting address of BSS to <addr>
+
+.. option:: -Ttext<addr>
+
+Set starting address of BSS to <addr>
+
+.. option:: -Wl,<arg>,<arg2>...
+
+Pass the comma separated arguments in <arg> to the linker
+
+.. option:: -X
+
+.. option:: -Xlinker <arg>, --for-linker <arg>, --for-linker=<arg>
+
+Pass <arg> to the linker
+
+.. program:: clang1
+.. option:: -Z
+.. program:: clang
+
+.. option:: -e<arg>, --entry
+
+.. option:: -filelist <arg>
+
+.. option:: -l<arg>
+
+.. option:: -r
+
+.. option:: -rpath <arg>
+
+.. option:: -s
+
+.. option:: -t
+
+.. option:: -u<arg>, --force-link <arg>, --force-link=<arg>
+
+.. option:: -undef
+
+undef all system defines
+
+.. option:: -undefined<arg>, --no-undefined
+
+.. option:: -z <arg>
+
+Pass -z <arg> to the linker
+
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst
index 3f76da6dca32..ed628e370087 100644
--- a/docs/ClangFormatStyleOptions.rst
+++ b/docs/ClangFormatStyleOptions.rst
@@ -213,6 +213,20 @@ the configuration (without a prefix: ``Auto``).
If ``true``, aligns escaped newlines as far left as possible.
Otherwise puts them into the right-most column.
+ .. code-block:: c++
+
+ true:
+ #define A \
+ int aaaa; \
+ int b; \
+ int dddddddddd;
+
+ false:
+ #define A \
+ int aaaa; \
+ int b; \
+ int dddddddddd;
+
**AlignOperands** (``bool``)
If ``true``, horizontally align operands of binary and ternary
expressions.
@@ -228,10 +242,23 @@ the configuration (without a prefix: ``Auto``).
**AlignTrailingComments** (``bool``)
If ``true``, aligns trailing comments.
+ .. code-block:: c++
+
+ true: false:
+ int a; // My comment a vs. int a; // My comment a
+ int b = 2; // comment b int b = 2; // comment about b
+
**AllowAllParametersOfDeclarationOnNextLine** (``bool``)
Allow putting all parameters of a function declaration onto
the next line even if ``BinPackParameters`` is ``false``.
+ .. code-block:: c++
+
+ true: false:
+ myFunction(foo, vs. myFunction(foo, bar, plop);
+ bar,
+ plop);
+
**AllowShortBlocksOnASingleLine** (``bool``)
Allows contracting simple braced statements to a single line.
@@ -240,6 +267,17 @@ the configuration (without a prefix: ``Auto``).
**AllowShortCaseLabelsOnASingleLine** (``bool``)
If ``true``, short case labels will be contracted to a single line.
+ .. code-block:: c++
+
+ true: false:
+ switch (a) { vs. switch (a) {
+ case 1: x = 1; break; case 1:
+ case 2: return; x = 1;
+ } break;
+ case 2:
+ return;
+ }
+
**AllowShortFunctionsOnASingleLine** (``ShortFunctionStyle``)
Dependent on the value, ``int f() { return 0; }`` can be put on a
single line.
@@ -252,12 +290,32 @@ the configuration (without a prefix: ``Auto``).
* ``SFS_Empty`` (in configuration: ``Empty``)
Only merge empty functions.
+ .. code-block:: c++
+
+ void f() { bar(); }
+ void f2() {
+ bar2();
+ }
+
* ``SFS_Inline`` (in configuration: ``Inline``)
Only merge functions defined inside a class. Implies "empty".
+ .. code-block:: c++
+
+ class Foo {
+ void f() { foo(); }
+ };
+
* ``SFS_All`` (in configuration: ``All``)
Merge all functions fitting on a single line.
+ .. code-block:: c++
+
+ class Foo {
+ void f() { foo(); }
+ };
+ void f() { bar(); }
+
**AllowShortIfStatementsOnASingleLine** (``bool``)
@@ -269,7 +327,7 @@ the configuration (without a prefix: ``Auto``).
**AlwaysBreakAfterDefinitionReturnType** (``DefinitionReturnTypeBreakingStyle``)
The function definition return type breaking style to use. This
- option is deprecated and is retained for backwards compatibility.
+ option is **deprecated** and is retained for backwards compatibility.
Possible values:
@@ -294,18 +352,78 @@ the configuration (without a prefix: ``Auto``).
Break after return type automatically.
``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
+ .. code-block:: c++
+
+ class A {
+ int f() { return 0; };
+ };
+ int f();
+ int f() { return 1; }
+
* ``RTBS_All`` (in configuration: ``All``)
Always break after the return type.
+ .. code-block:: c++
+
+ class A {
+ int
+ f() {
+ return 0;
+ };
+ };
+ int
+ f();
+ int
+ f() {
+ return 1;
+ }
+
* ``RTBS_TopLevel`` (in configuration: ``TopLevel``)
Always break after the return types of top-level functions.
+ .. code-block:: c++
+
+ class A {
+ int f() { return 0; };
+ };
+ int
+ f();
+ int
+ f() {
+ return 1;
+ }
+
* ``RTBS_AllDefinitions`` (in configuration: ``AllDefinitions``)
Always break after the return type of function definitions.
+ .. code-block:: c++
+
+ class A {
+ int
+ f() {
+ return 0;
+ };
+ };
+ int f();
+ int
+ f() {
+ return 1;
+ }
+
* ``RTBS_TopLevelDefinitions`` (in configuration: ``TopLevelDefinitions``)
Always break after the return type of top-level definitions.
+ .. code-block:: c++
+
+ class A {
+ int f() { return 0; };
+ };
+ int f();
+ int
+ f() {
+ return 1;
+ }
+
**AlwaysBreakBeforeMultilineStrings** (``bool``)
@@ -316,18 +434,57 @@ the configuration (without a prefix: ``Auto``).
the string at that point leads to it being indented
``ContinuationIndentWidth`` spaces from the start of the line.
+ .. code-block:: c++
+
+ true: false:
+ aaaa = vs. aaaa = "bbbb"
+ "bbbb" "cccc";
+ "cccc";
+
**AlwaysBreakTemplateDeclarations** (``bool``)
If ``true``, always break after the ``template<...>`` of a template
declaration.
+ .. code-block:: c++
+
+ true: false:
+ template <typename T> vs. template <typename T> class C {};
+ class C {};
+
**BinPackArguments** (``bool``)
If ``false``, a function call's arguments will either be all on the
same line or will have one line each.
+ .. code-block:: c++
+
+ true:
+ void f() {
+ f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa,
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
+ }
+
+ false:
+ void f() {
+ f(aaaaaaaaaaaaaaaaaaaa,
+ aaaaaaaaaaaaaaaaaaaa,
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
+ }
+
**BinPackParameters** (``bool``)
If ``false``, a function declaration's or function definition's
parameters will either all be on the same line or will have one line each.
+ .. code-block:: c++
+
+ true:
+ void f(int aaaaaaaaaaaaaaaaaaaa, int aaaaaaaaaaaaaaaaaaaa,
+ int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
+
+ false:
+ void f(int aaaaaaaaaaaaaaaaaaaa,
+ int aaaaaaaaaaaaaaaaaaaa,
+ int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
+
**BraceWrapping** (``BraceWrappingFlags``)
Control of individual brace wrapping cases.
@@ -336,22 +493,161 @@ the configuration (without a prefix: ``Auto``).
Nested configuration flags:
+
* ``bool AfterClass`` Wrap class definitions.
+
+ .. code-block:: c++
+
+ true:
+ class foo {};
+
+ false:
+ class foo
+ {};
+
* ``bool AfterControlStatement`` Wrap control statements (``if``/``for``/``while``/``switch``/..).
+
+ .. code-block:: c++
+
+ true:
+ if (foo())
+ {
+ } else
+ {}
+ for (int i = 0; i < 10; ++i)
+ {}
+
+ false:
+ if (foo()) {
+ } else {
+ }
+ for (int i = 0; i < 10; ++i) {
+ }
+
* ``bool AfterEnum`` Wrap enum definitions.
+
+ .. code-block:: c++
+
+ true:
+ enum X : int
+ {
+ B
+ };
+
+ false:
+ enum X : int { B };
+
* ``bool AfterFunction`` Wrap function definitions.
+
+ .. code-block:: c++
+
+ true:
+ void foo()
+ {
+ bar();
+ bar2();
+ }
+
+ false:
+ void foo() {
+ bar();
+ bar2();
+ }
+
* ``bool AfterNamespace`` Wrap namespace definitions.
+
+ .. code-block:: c++
+
+ true:
+ namespace
+ {
+ int foo();
+ int bar();
+ }
+
+ false:
+ namespace {
+ int foo();
+ int bar();
+ }
+
* ``bool AfterObjCDeclaration`` Wrap ObjC definitions (``@autoreleasepool``, interfaces, ..).
+
* ``bool AfterStruct`` Wrap struct definitions.
+
+ .. code-block:: c++
+
+ true:
+ struct foo
+ {
+ int x;
+ }
+
+ false:
+ struct foo {
+ int x;
+ }
+
* ``bool AfterUnion`` Wrap union definitions.
+
+ .. code-block:: c++
+
+ true:
+ union foo
+ {
+ int x;
+ }
+
+ false:
+ union foo {
+ int x;
+ }
+
* ``bool BeforeCatch`` Wrap before ``catch``.
+
+ .. code-block:: c++
+
+ true:
+ try {
+ foo();
+ }
+ catch () {
+ }
+
+ false:
+ try {
+ foo();
+ } catch () {
+ }
+
* ``bool BeforeElse`` Wrap before ``else``.
+
+ .. code-block:: c++
+
+ true:
+ if (foo()) {
+ }
+ else {
+ }
+
+ false:
+ if (foo()) {
+ } else {
+ }
+
* ``bool IndentBraces`` Indent the wrapped braces themselves.
**BreakAfterJavaFieldAnnotations** (``bool``)
Break after each annotation on a field in Java files.
+ .. code-block:: java
+
+ true: false:
+ @Partial vs. @Partial @Mock DataLoad loader;
+ @Mock
+ DataLoad loader;
+
**BreakBeforeBinaryOperators** (``BinaryOperatorStyle``)
The way to wrap binary operators.
@@ -360,12 +656,45 @@ the configuration (without a prefix: ``Auto``).
* ``BOS_None`` (in configuration: ``None``)
Break after operators.
+ .. code-block:: c++
+
+ LooooooooooongType loooooooooooooooooooooongVariable =
+ someLooooooooooooooooongFunction();
+
+ bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >
+ ccccccccccccccccccccccccccccccccccccccccc;
+
* ``BOS_NonAssignment`` (in configuration: ``NonAssignment``)
Break before operators that aren't assignments.
+ .. code-block:: c++
+
+ LooooooooooongType loooooooooooooooooooooongVariable =
+ someLooooooooooooooooongFunction();
+
+ bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ > ccccccccccccccccccccccccccccccccccccccccc;
+
* ``BOS_All`` (in configuration: ``All``)
Break before operators.
+ .. code-block:: c++
+
+ LooooooooooongType loooooooooooooooooooooongVariable
+ = someLooooooooooooooooongFunction();
+
+ bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ > ccccccccccccccccccccccccccccccccccccccccc;
+
**BreakBeforeBraces** (``BraceBreakingStyle``)
@@ -376,41 +705,190 @@ the configuration (without a prefix: ``Auto``).
* ``BS_Attach`` (in configuration: ``Attach``)
Always attach braces to surrounding context.
+ .. code-block:: c++
+
+ try {
+ foo();
+ } catch () {
+ }
+ void foo() { bar(); }
+ class foo {};
+ if (foo()) {
+ } else {
+ }
+ enum X : int { A, B };
+
* ``BS_Linux`` (in configuration: ``Linux``)
Like ``Attach``, but break before braces on function, namespace and
class definitions.
+ .. code-block:: c++
+
+ try {
+ foo();
+ } catch () {
+ }
+ void foo() { bar(); }
+ class foo
+ {
+ };
+ if (foo()) {
+ } else {
+ }
+ enum X : int { A, B };
+
* ``BS_Mozilla`` (in configuration: ``Mozilla``)
Like ``Attach``, but break before braces on enum, function, and record
definitions.
+ .. code-block:: c++
+
+ try {
+ foo();
+ } catch () {
+ }
+ void foo() { bar(); }
+ class foo
+ {
+ };
+ if (foo()) {
+ } else {
+ }
+ enum X : int { A, B };
+
* ``BS_Stroustrup`` (in configuration: ``Stroustrup``)
Like ``Attach``, but break before function definitions, ``catch``, and
``else``.
+ .. code-block:: c++
+
+ try {
+ foo();
+ } catch () {
+ }
+ void foo() { bar(); }
+ class foo
+ {
+ };
+ if (foo()) {
+ } else {
+ }
+ enum X : int
+ {
+ A,
+ B
+ };
+
* ``BS_Allman`` (in configuration: ``Allman``)
Always break before braces.
+ .. code-block:: c++
+
+ try {
+ foo();
+ }
+ catch () {
+ }
+ void foo() { bar(); }
+ class foo {
+ };
+ if (foo()) {
+ }
+ else {
+ }
+ enum X : int { A, B };
+
* ``BS_GNU`` (in configuration: ``GNU``)
Always break before braces and add an extra level of indentation to
braces of control statements, not to those of class, function
or other definitions.
+ .. code-block:: c++
+
+ try
+ {
+ foo();
+ }
+ catch ()
+ {
+ }
+ void foo() { bar(); }
+ class foo
+ {
+ };
+ if (foo())
+ {
+ }
+ else
+ {
+ }
+ enum X : int
+ {
+ A,
+ B
+ };
+
* ``BS_WebKit`` (in configuration: ``WebKit``)
Like ``Attach``, but break before functions.
+ .. code-block:: c++
+
+ try {
+ foo();
+ } catch () {
+ }
+ void foo() { bar(); }
+ class foo {
+ };
+ if (foo()) {
+ } else {
+ }
+ enum X : int { A, B };
+
* ``BS_Custom`` (in configuration: ``Custom``)
Configure each individual brace in `BraceWrapping`.
+**BreakBeforeInheritanceComma** (``bool``)
+ If ``true``, in the class inheritance expression clang-format will
+ break before ``:`` and ``,`` if there is multiple inheritance.
+
+ .. code-block:: c++
+
+ true: false:
+ class MyClass vs. class MyClass : public X, public Y {
+ : public X };
+ , public Y {
+ };
+
**BreakBeforeTernaryOperators** (``bool``)
If ``true``, ternary operators will be placed after line breaks.
+ .. code-block:: c++
+
+ true:
+ veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription
+ ? firstValue
+ : SecondValueVeryVeryVeryVeryLong;
+
+ true:
+ veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ?
+ firstValue :
+ SecondValueVeryVeryVeryVeryLong;
+
**BreakConstructorInitializersBeforeComma** (``bool``)
Always break constructor initializers before commas and align
the commas with the colon.
+ .. code-block:: c++
+
+ true: false:
+ SomeClass::Constructor() vs. SomeClass::Constructor() : a(a),
+ : a(a) b(b),
+ , b(b) c(c) {}
+ , c(c) {}
+
**BreakStringLiterals** (``bool``)
Allow breaking string literals when formatting.
@@ -425,10 +903,31 @@ the configuration (without a prefix: ``Auto``).
A regular expression that describes comments with special meaning,
which should not be split into lines or otherwise changed.
+ .. code-block:: c++
+
+ // CommentPragmas: '^ FOOBAR pragma:'
+ // Will leave the following line unaffected
+ #include <vector> // FOOBAR pragma: keep
+
**ConstructorInitializerAllOnOneLineOrOnePerLine** (``bool``)
If the constructor initializers don't fit on a line, put each
initializer on its own line.
+ .. code-block:: c++
+
+ true:
+ SomeClass::Constructor()
+ : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) {
+ return 0;
+ }
+
+ false:
+ SomeClass::Constructor()
+ : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa),
+ aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) {
+ return 0;
+ }
+
**ConstructorInitializerIndentWidth** (``unsigned``)
The number of characters to use for indentation of constructor
initializer lists.
@@ -436,6 +935,14 @@ the configuration (without a prefix: ``Auto``).
**ContinuationIndentWidth** (``unsigned``)
Indent width for line continuations.
+ .. code-block:: c++
+
+ ContinuationIndentWidth: 2
+
+ int i = // VeryVeryVeryVeryVeryLongComment
+ longFunction( // Again a long comment
+ arg);
+
**Cpp11BracedListStyle** (``bool``)
If ``true``, format braced lists as best suited for C++11 braced
lists.
@@ -451,10 +958,20 @@ the configuration (without a prefix: ``Auto``).
the parentheses of a function call with that name. If there is no name,
a zero-length name is assumed.
+ .. code-block:: c++
+
+ true: false:
+ vector<int> x{1, 2, 3, 4}; vs. vector<int> x{ 1, 2, 3, 4 };
+ vector<T> x{{}, {}, {}, {}}; vector<T> x{ {}, {}, {}, {} };
+ f(MyMap[{composite, key}]); f(MyMap[{ composite, key }]);
+ new int[3]{1, 2, 3}; new int[3]{ 1, 2, 3 };
+
**DerivePointerAlignment** (``bool``)
If ``true``, analyze the formatted file for the most common
- alignment of ``&`` and ``\*``. ``PointerAlignment`` is then used only as
- fallback.
+ alignment of ``&`` and ``*``.
+ Pointer and reference alignment styles are going to be updated according
+ to the preferences found in the file.
+ ``PointerAlignment`` is then used only as fallback.
**DisableFormat** (``bool``)
Disables formatting completely.
@@ -471,6 +988,17 @@ the configuration (without a prefix: ``Auto``).
NOTE: This is an experimental flag, that might go away or be renamed. Do
not use this in config files, etc. Use at your own risk.
+**FixNamespaceComments** (``bool``)
+ If ``true``, clang-format adds missing namespace end comments and
+ fixes invalid existing ones.
+
+ .. code-block:: c++
+
+ true: false:
+ namespace a { vs. namespace a {
+ foo(); foo();
+ } // namespace a; }
+
**ForEachMacros** (``std::vector<std::string>``)
A vector of macros that should be interpreted as foreach loops
instead of as function calls.
@@ -516,7 +1044,7 @@ the configuration (without a prefix: ``Auto``).
Priority: 2
- Regex: '^(<|"(gtest|isl|json)/)'
Priority: 3
- - Regex: '.\*'
+ - Regex: '.*'
Priority: 1
**IncludeIsMainRegex** (``std::string``)
@@ -538,13 +1066,45 @@ the configuration (without a prefix: ``Auto``).
When ``false``, use the same indentation level as for the switch statement.
Switch statement body is always indented one level more than case labels.
+ .. code-block:: c++
+
+ false: true:
+ switch (fool) { vs. switch (fool) {
+ case 1: case 1:
+ bar(); bar();
+ break; break;
+ default: default:
+ plop(); plop();
+ } }
+
**IndentWidth** (``unsigned``)
The number of columns to use for indentation.
+ .. code-block:: c++
+
+ IndentWidth: 3
+
+ void f() {
+ someFunction();
+ if (true, false) {
+ f();
+ }
+ }
+
**IndentWrappedFunctionNames** (``bool``)
Indent if a function definition or declaration is wrapped after the
type.
+ .. code-block:: c++
+
+ true:
+ LoooooooooooooooooooooooooooooooooooooooongReturnType
+ LoooooooooooooooooooooooooooooooongFunctionDeclaration();
+
+ false:
+ LoooooooooooooooooooooooooooooooooooooooongReturnType
+ LoooooooooooooooooooooooooooooooongFunctionDeclaration();
+
**JavaScriptQuotes** (``JavaScriptQuoteStyle``)
The JavaScriptQuoteStyle to use for JavaScript strings.
@@ -553,16 +1113,54 @@ the configuration (without a prefix: ``Auto``).
* ``JSQS_Leave`` (in configuration: ``Leave``)
Leave string quotes as they are.
+ .. code-block:: js
+
+ string1 = "foo";
+ string2 = 'bar';
+
* ``JSQS_Single`` (in configuration: ``Single``)
Always use single quotes.
+ .. code-block:: js
+
+ string1 = 'foo';
+ string2 = 'bar';
+
* ``JSQS_Double`` (in configuration: ``Double``)
Always use double quotes.
+ .. code-block:: js
+
+ string1 = "foo";
+ string2 = "bar";
+
+
+**JavaScriptWrapImports** (``bool``)
+ Whether to wrap JavaScript import/export statements.
+
+ .. code-block:: js
+
+ true:
+ import {
+ VeryLongImportsAreAnnoying,
+ VeryLongImportsAreAnnoying,
+ VeryLongImportsAreAnnoying,
+ } from 'some/module.js'
+
+ false:
+ import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js"
**KeepEmptyLinesAtTheStartOfBlocks** (``bool``)
- If true, empty lines at the start of blocks are kept.
+ If true, the empty line at the start of blocks is kept.
+
+ .. code-block:: c++
+
+ true: false:
+ if (foo) { vs. if (foo) {
+ bar();
+ bar(); }
+ }
**Language** (``LanguageKind``)
Language, this format style is targeted at.
@@ -573,7 +1171,7 @@ the configuration (without a prefix: ``Auto``).
Do not use.
* ``LK_Cpp`` (in configuration: ``Cpp``)
- Should be used for C, C++, ObjectiveC, ObjectiveC++.
+ Should be used for C, C++.
* ``LK_Java`` (in configuration: ``Java``)
Should be used for Java.
@@ -581,6 +1179,9 @@ the configuration (without a prefix: ``Auto``).
* ``LK_JavaScript`` (in configuration: ``JavaScript``)
Should be used for JavaScript.
+ * ``LK_ObjC`` (in configuration: ``ObjC``)
+ Should be used for Objective-C, Objective-C++.
+
* ``LK_Proto`` (in configuration: ``Proto``)
Should be used for Protocol Buffers
(https://developers.google.com/protocol-buffers/).
@@ -593,12 +1194,49 @@ the configuration (without a prefix: ``Auto``).
**MacroBlockBegin** (``std::string``)
A regular expression matching macros that start a block.
+ .. code-block:: c++
+
+ # With:
+ MacroBlockBegin: "^NS_MAP_BEGIN|\
+ NS_TABLE_HEAD$"
+ MacroBlockEnd: "^\
+ NS_MAP_END|\
+ NS_TABLE_.*_END$"
+
+ NS_MAP_BEGIN
+ foo();
+ NS_MAP_END
+
+ NS_TABLE_HEAD
+ bar();
+ NS_TABLE_FOO_END
+
+ # Without:
+ NS_MAP_BEGIN
+ foo();
+ NS_MAP_END
+
+ NS_TABLE_HEAD
+ bar();
+ NS_TABLE_FOO_END
+
**MacroBlockEnd** (``std::string``)
A regular expression matching macros that end a block.
**MaxEmptyLinesToKeep** (``unsigned``)
The maximum number of consecutive empty lines to keep.
+ .. code-block:: c++
+
+ MaxEmptyLinesToKeep: 1 vs. MaxEmptyLinesToKeep: 0
+ int f() { int f() {
+ int = 1; int i = 1;
+ i = foo();
+ i = foo(); return i;
+ }
+ return i;
+ }
+
**NamespaceIndentation** (``NamespaceIndentationKind``)
The indentation used for namespaces.
@@ -607,17 +1245,52 @@ the configuration (without a prefix: ``Auto``).
* ``NI_None`` (in configuration: ``None``)
Don't indent in namespaces.
+ .. code-block:: c++
+
+ namespace out {
+ int i;
+ namespace in {
+ int i;
+ }
+ }
+
* ``NI_Inner`` (in configuration: ``Inner``)
Indent only in inner namespaces (nested in other namespaces).
+ .. code-block:: c++
+
+ namespace out {
+ int i;
+ namespace in {
+ int i;
+ }
+ }
+
* ``NI_All`` (in configuration: ``All``)
Indent in all namespaces.
+ .. code-block:: c++
+
+ namespace out {
+ int i;
+ namespace in {
+ int i;
+ }
+ }
+
**ObjCBlockIndentWidth** (``unsigned``)
The number of characters to use for indentation of ObjC blocks.
+ .. code-block:: objc
+
+ ObjCBlockIndentWidth: 4
+
+ [operation setCompletionBlock:^{
+ [self onOperationDone];
+ }];
+
**ObjCSpaceAfterProperty** (``bool``)
Add a space after ``@property`` in Objective-C, i.e. use
``@property (readonly)`` instead of ``@property(readonly)``.
@@ -653,29 +1326,75 @@ the configuration (without a prefix: ``Auto``).
* ``PAS_Left`` (in configuration: ``Left``)
Align pointer to the left.
+ .. code-block:: c++
+
+ int* a;
+
* ``PAS_Right`` (in configuration: ``Right``)
Align pointer to the right.
+ .. code-block:: c++
+
+ int *a;
+
* ``PAS_Middle`` (in configuration: ``Middle``)
Align pointer in the middle.
+ .. code-block:: c++
+
+ int * a;
+
**ReflowComments** (``bool``)
If ``true``, clang-format will attempt to re-flow comments.
+ .. code-block:: c++
+
+ false:
+ // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
+ /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
+
+ true:
+ // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
+ // information
+ /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
+ * information */
+
**SortIncludes** (``bool``)
If ``true``, clang-format will sort ``#includes``.
+ .. code-block:: c++
+
+ false: true:
+ #include "b.h" vs. #include "a.h"
+ #include "a.h" #include "b.h"
+
**SpaceAfterCStyleCast** (``bool``)
- If ``true``, a space may be inserted after C style casts.
+ If ``true``, a space is inserted after C style casts.
+
+ .. code-block:: c++
+
+ true: false:
+ (int)i; vs. (int) i;
**SpaceAfterTemplateKeyword** (``bool``)
If ``true``, a space will be inserted after the 'template' keyword.
+ .. code-block:: c++
+
+ true: false:
+ template <int> void foo(); vs. template<int> void foo();
+
**SpaceBeforeAssignmentOperators** (``bool``)
If ``false``, spaces will be removed before assignment operators.
+ .. code-block:: c++
+
+ true: false:
+ int a = 5; vs. int a=5;
+ a += 42 a+=42;
+
**SpaceBeforeParens** (``SpaceBeforeParensOptions``)
Defines in which cases to put a space before opening parentheses.
@@ -684,21 +1403,55 @@ the configuration (without a prefix: ``Auto``).
* ``SBPO_Never`` (in configuration: ``Never``)
Never put a space before opening parentheses.
+ .. code-block:: c++
+
+ void f() {
+ if(true) {
+ f();
+ }
+ }
+
* ``SBPO_ControlStatements`` (in configuration: ``ControlStatements``)
Put a space before opening parentheses only after control statement
keywords (``for/if/while...``).
+ .. code-block:: c++
+
+ void f() {
+ if (true) {
+ f();
+ }
+ }
+
* ``SBPO_Always`` (in configuration: ``Always``)
Always put a space before opening parentheses, except when it's
prohibited by the syntax rules (in function-like macro definitions) or
when determined by other style rules (after unary operators, opening
parentheses, etc.)
+ .. code-block:: c++
+
+ void f () {
+ if (true) {
+ f ();
+ }
+ }
+
**SpaceInEmptyParentheses** (``bool``)
If ``true``, spaces may be inserted into ``()``.
+ .. code-block:: c++
+
+ true: false:
+ void f( ) { vs. void f() {
+ int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()};
+ if (true) { if (true) {
+ f( ); f();
+ } }
+ } }
+
**SpacesBeforeTrailingComments** (``unsigned``)
The number of spaces before trailing line comments
(``//`` - comments).
@@ -707,22 +1460,60 @@ the configuration (without a prefix: ``Auto``).
those commonly have different usage patterns and a number of special
cases.
+ .. code-block:: c++
+
+ SpacesBeforeTrailingComments: 3
+ void f() {
+ if (true) { // foo1
+ f(); // bar
+ } // foo
+ }
+
**SpacesInAngles** (``bool``)
If ``true``, spaces will be inserted after ``<`` and before ``>``
in template argument lists.
+ .. code-block:: c++
+
+ true: false:
+ static_cast< int >(arg); vs. static_cast<int>(arg);
+ std::function< void(int) > fct; std::function<void(int)> fct;
+
**SpacesInCStyleCastParentheses** (``bool``)
If ``true``, spaces may be inserted into C style casts.
+ .. code-block:: c++
+
+ true: false:
+ x = ( int32 )y vs. x = (int32)y
+
**SpacesInContainerLiterals** (``bool``)
If ``true``, spaces are inserted inside container literals (e.g.
ObjC and Javascript array and dict literals).
+ .. code-block:: js
+
+ true: false:
+ var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3];
+ f({a : 1, b : 2, c : 3}); f({a: 1, b: 2, c: 3});
+
**SpacesInParentheses** (``bool``)
If ``true``, spaces will be inserted after ``(`` and before ``)``.
+ .. code-block:: c++
+
+ true: false:
+ t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
+
**SpacesInSquareBrackets** (``bool``)
If ``true``, spaces will be inserted after ``[`` and before ``]``.
+ Lambdas or unspecified size array declarations will not be affected.
+
+ .. code-block:: c++
+
+ true: false:
+ int a[ 5 ]; vs. int a[5];
+ std::unique_ptr<int[]> foo() {} // Won't be affected
**Standard** (``LanguageStandard``)
Format compatible with this standard, e.g. use ``A<A<int> >``
@@ -734,7 +1525,8 @@ the configuration (without a prefix: ``Auto``).
Use C++03-compatible syntax.
* ``LS_Cpp11`` (in configuration: ``Cpp11``)
- Use features of C++11 (e.g. ``A<A<int>>`` instead of ``A<A<int> >``).
+ Use features of C++11, C++14 and C++1z (e.g. ``A<A<int>>`` instead of
+ ``A<A<int> >``).
* ``LS_Auto`` (in configuration: ``Auto``)
Automatic detection based on the input.
@@ -755,6 +1547,9 @@ the configuration (without a prefix: ``Auto``).
* ``UT_ForIndentation`` (in configuration: ``ForIndentation``)
Use tabs only for indentation.
+ * ``UT_ForContinuationAndIndentation`` (in configuration: ``ForContinuationAndIndentation``)
+ Use tabs only for line continuation and indentation.
+
* ``UT_Always`` (in configuration: ``Always``)
Use tabs whenever we need to fill whitespace that spans at least from
one tab stop to the next one.
@@ -872,4 +1667,3 @@ The result is:
r();
}
}
-
diff --git a/docs/ControlFlowIntegrityDesign.rst b/docs/ControlFlowIntegrityDesign.rst
index a9f0b28a95f5..69b72f9ea5b2 100644
--- a/docs/ControlFlowIntegrityDesign.rst
+++ b/docs/ControlFlowIntegrityDesign.rst
@@ -498,12 +498,100 @@ In non-PIE executables the address of an external function (taken from
the main executable) is the address of that function’s PLT record in
the main executable. This would break the CFI checks.
+Backward-edge CFI for return statements (RCFI)
+==============================================
+
+This section is a proposal. As of March 2017 it is not implemented.
+
+Backward-edge control flow (`RET` instructions) can be hijacked
+via overwriting the return address (`RA`) on stack.
+Various mitigation techniques (e.g. `SafeStack`_, `RFG`_, `Intel CET`_)
+try to detect or prevent `RA` corruption on stack.
+
+RCFI enforces the expected control flow in several different ways described below.
+RCFI heavily relies on LTO.
+
+Leaf Functions
+--------------
+If `f()` is a leaf function (i.e. it has no calls
+except maybe no-return calls) it can be called using a special calling convention
+that stores `RA` in a dedicated register `R` before the `CALL` instruction.
+`f()` does not spill `R` and does not use the `RET` instruction,
+instead it uses the value in `R` to `JMP` to `RA`.
+
+This flavour of CFI is *precise*, i.e. the function is guaranteed to return
+to the point exactly following the call.
+
+An alternative approach is to
+copy `RA` from stack to `R` in the first instruction of `f()`,
+then `JMP` to `R`.
+This approach is simpler to implement (does not require changing the caller)
+but weaker (there is a small window when `RA` is actually stored on stack).
+
+
+Functions called once
+---------------------
+Suppose `f()` is called in just one place in the program
+(assuming we can verify this in LTO mode).
+In this case we can replace the `RET` instruction with a `JMP` instruction
+with the immediate constant for `RA`.
+This will *precisely* enforce the return control flow no matter what is stored on stack.
+
+Another variant is to compare `RA` on stack with the known constant and abort
+if they don't match; then `JMP` to the known constant address.
+
+Functions called in a small number of call sites
+------------------------------------------------
+We may extend the above approach to cases where `f()`
+is called more than once (but still a small number of times).
+With LTO we know all possible values of `RA` and we check them
+one-by-one (or using binary search) against the value on stack.
+If the match is found, we `JMP` to the known constant address, otherwise abort.
+
+This protection is *near-precise*, i.e. it guarantees that the control flow will
+be transferred to one of the valid return addresses for this function,
+but not necessary to the point of the most recent `CALL`.
+
+General case
+------------
+For functions called multiple times a *return jump table* is constructed
+in the same manner as jump tables for indirect function calls (see above).
+The correct jump table entry (or it's index) is passed by `CALL` to `f()`
+(as an extra argument) and then spilled to stack.
+The `RET` instruction is replaced with a load of the jump table entry,
+jump table range check, and `JMP` to the jump table entry.
+
+This protection is also *near-precise*.
+
+Returns from functions called indirectly
+----------------------------------------
+
+If a function is called indirectly, the return jump table is constructed for the
+equivalence class of functions instead of a single function.
+
+Cross-DSO calls
+---------------
+Consider two instrumented DSOs, `A` and `B`. `A` defines `f()` and `B` calls it.
+
+This case will be handled similarly to the cross-DSO scheme using the slow path callback.
+
+Non-goals
+---------
+
+RCFI does not protect `RET` instructions:
+ * in non-instrumented DSOs,
+ * in instrumented DSOs for functions that are called from non-instrumented DSOs,
+ * embedded into other instructions (e.g. `0f4fc3 cmovg %ebx,%eax`).
+
+.. _SafeStack: https://clang.llvm.org/docs/SafeStack.html
+.. _RFG: http://xlab.tencent.com/en/2016/11/02/return-flow-guard
+.. _Intel CET: https://software.intel.com/en-us/blogs/2016/06/09/intel-release-new-technology-specifications-protect-rop-attacks
Hardware support
================
We believe that the above design can be efficiently implemented in hardware.
-A single new instruction added to an ISA would allow to perform the CFI check
+A single new instruction added to an ISA would allow to perform the forward-edge CFI check
with fewer bytes per check (smaller code size overhead) and potentially more
efficiently. The current software-only instrumentation requires at least
32-bytes per check (on x86_64).
@@ -540,7 +628,7 @@ The bit vector lookup is probably too complex for a hardware implementation.
Jump(kFailedCheckTarget);
}
-An alternative and more compact enconding would not use `kFailedCheckTarget`,
+An alternative and more compact encoding would not use `kFailedCheckTarget`,
and will trap on check failure instead.
This will allow us to fit the instruction into **8-9 bytes**.
The cross-DSO checks will be performed by a trap handler and
diff --git a/docs/DiagnosticsReference.rst b/docs/DiagnosticsReference.rst
index 7294c3662027..d8c486fc3b3c 100644
--- a/docs/DiagnosticsReference.rst
+++ b/docs/DiagnosticsReference.rst
@@ -251,6 +251,28 @@ Some of the diagnostics controlled by this flag are enabled by default.
Controls `-Wmost`_, `-Wparentheses`_, `-Wswitch`_, `-Wswitch-bool`_.
+-Walloca-with-align-alignof
+---------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`second argument to \_\_builtin\_alloca\_with\_align is supposed to be in bits`|
++--------------------------------------------------------------------------------------------------------------------+
+
+
+-Wambiguous-delete
+------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`multiple suitable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`functions for` |nbsp| :placeholder:`B`:diagtext:`; no 'operator delete' function will be invoked if initialization throws an exception`|
++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wambiguous-ellipsis
--------------------
This diagnostic is enabled by default.
@@ -482,7 +504,24 @@ This diagnostic is enabled by default.
-Wasm
-----
-Synonym for `-Wasm-operand-widths`_.
+This diagnostic is enabled by default.
+
+Controls `-Wasm-ignored-qualifier`_, `-Wasm-operand-widths`_.
+
+
+-Wasm-ignored-qualifier
+-----------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignored` |nbsp| :placeholder:`A` |nbsp| :diagtext:`qualifier on asm`|
++----------------------------------------------------------------------------------------------------------+
+
++-------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`meaningless 'volatile' on asm outside function`|
++-------------------------------------------------------------------------------------+
-Wasm-operand-widths
@@ -697,21 +736,6 @@ This diagnostic is enabled by default.
+-------------------------------------------------------------------------------+
--Wbad-array-new-length
-----------------------
-This diagnostic is enabled by default.
-
-**Diagnostic text:**
-
-+--------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`array is too large (`:placeholder:`A` |nbsp| :diagtext:`elements)`|
-+--------------------------------------------------------------------------------------------------------+
-
-+-------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`array size is negative`|
-+-------------------------------------------------------------+
-
-
-Wbad-function-cast
-------------------
**Diagnostic text:**
@@ -768,9 +792,26 @@ This diagnostic is enabled by default.
**Diagnostic text:**
-+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`implicit truncation from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to bitfield changes value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`|
-+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`implicit truncation from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to bit-field changes value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`|
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wbitfield-enum-conversion
+--------------------------
+**Diagnostic text:**
+
++------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`bit-field` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not wide enough to store all enumerators of` |nbsp| :placeholder:`B`|
++------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`signed bit-field` |nbsp| :placeholder:`A` |nbsp| :diagtext:`needs an extra bit to represent the largest positive enumerators of` |nbsp| :placeholder:`B`|
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`assigning value of signed enum type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`to unsigned bit-field` |nbsp| :placeholder:`A`:diagtext:`; negative enumerators of enum` |nbsp| :placeholder:`B` |nbsp| :diagtext:`will be converted to positive values`|
++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-Wbitfield-width
@@ -807,6 +848,17 @@ This diagnostic is enabled by default.
+-----------------------------------------------------------------------------------------------------------+
+-Wblock-capture-autoreleasing
+-----------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`block captures an autoreleasing out-parameter, which may result in use-after-free bugs`|
++-----------------------------------------------------------------------------------------------------------------------------+
+
+
-Wbool-conversion
-----------------
This diagnostic is enabled by default.
@@ -1306,7 +1358,13 @@ Synonym for `-Wc++14-extensions`_.
--------------
This diagnostic is enabled by default.
-Controls `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_.
+Also controls `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`mangled name of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`will change in C++17 due to non-throwing exception specification in function signature`|
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-Wc++1z-extensions
@@ -1343,10 +1401,22 @@ Some of the diagnostics controlled by this flag are enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++1z feature`|
+----------------------------------------------------------------------------------------+
++----------------------------------------+--------------------+-------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`'`|+------------------+|:diagtext:`' initialization statements are a C++1z extension`|
+| ||:diagtext:`if` || |
+| |+------------------+| |
+| ||:diagtext:`switch`|| |
+| |+------------------+| |
++----------------------------------------+--------------------+-------------------------------------------------------------+
+
+-----------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`inline variables are a C++1z extension`|
+-----------------------------------------------------------------------------+
++---------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`use of multiple declarators in a single using declaration is a C++1z extension`|
++---------------------------------------------------------------------------------------------------------------------+
+
+-------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is a C++1z extension; define each namespace separately`|
+-------------------------------------------------------------------------------------------------------------------------+
@@ -1367,6 +1437,10 @@ Some of the diagnostics controlled by this flag are enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is a C++1z extension`|
+--------------------------------------------------------------------------------------------------+
++-----------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`pack expansion of using declaration is a C++1z extension`|
++-----------------------------------------------------------------------------------------------+
+
-Wc++98-c++11-c++14-compat
--------------------------
@@ -1396,6 +1470,14 @@ Some of the diagnostics controlled by this flag are enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is incompatible with C++ standards before C++1z`|
+-----------------------------------------------------------------------------------------------------------+
++---------------------------+--------------------+----------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| |+------------------+| |nbsp| :diagtext:`initialization statements are incompatible with C++ standards before C++1z`|
+| ||:diagtext:`if` || |
+| |+------------------+| |
+| ||:diagtext:`switch`|| |
+| |+------------------+| |
++---------------------------+--------------------+----------------------------------------------------------------------------------------------+
+
+--------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`inline variables are incompatible with C++ standards before C++1z`|
+--------------------------------------------------------------------------------------------------------+
@@ -1412,6 +1494,10 @@ Some of the diagnostics controlled by this flag are enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is incompatible with C++ standards before C++1z`|
+---------------------------------------------------------------------------------------------------------------------+
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`non-type template parameters declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`are incompatible with C++ standards before C++1z`|
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+-----------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is incompatible with C++ standards before C++1z`|
+-----------------------------------------------------------------------------------------------------------------------------------+
@@ -1424,6 +1510,14 @@ Some of the diagnostics controlled by this flag are enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is incompatible with C++ standards before C++1z`|
+-----------------------------------------------------------------------------------------------------------------------------+
++------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`use of multiple declarators in a single using declaration is incompatible with C++ standards before C++1z`|
++------------------------------------------------------------------------------------------------------------------------------------------------+
+
++-----------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`pack expansion using declaration is incompatible with C++ standards before C++1z`|
++-----------------------------------------------------------------------------------------------------------------------+
+
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`'begin' and 'end' returning different types (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`) is incompatible with C++ standards before C++1z`|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -1436,7 +1530,7 @@ Also controls `-Wc++98-c++11-c++14-compat`_.
**Diagnostic text:**
+---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`hexidecimal floating literals are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are incompatible with C++ standards before C++1z`|
+---------------------------------------------------------------------------------------------------------------------+
@@ -2176,10 +2270,6 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`comparison of distinct pointer types`|
+---------------------------------------------------------------------------+
-+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`comparison of distinct pointer types (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`) uses non-standard composite pointer type` |nbsp| :placeholder:`C`|
-+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-
-Wcomplex-component-init
------------------------
@@ -2309,7 +2399,7 @@ This diagnostic is enabled by default.
------------
Some of the diagnostics controlled by this flag are enabled by default.
-Also controls `-Wbool-conversion`_, `-Wconstant-conversion`_, `-Wenum-conversion`_, `-Wfloat-conversion`_, `-Wint-conversion`_, `-Wliteral-conversion`_, `-Wnon-literal-null-conversion`_, `-Wnull-conversion`_, `-Wobjc-literal-conversion`_, `-Wshorten-64-to-32`_, `-Wsign-conversion`_, `-Wstring-conversion`_.
+Also controls `-Wbitfield-enum-conversion`_, `-Wbool-conversion`_, `-Wconstant-conversion`_, `-Wenum-conversion`_, `-Wfloat-conversion`_, `-Wint-conversion`_, `-Wliteral-conversion`_, `-Wnon-literal-null-conversion`_, `-Wnull-conversion`_, `-Wobjc-literal-conversion`_, `-Wshorten-64-to-32`_, `-Wsign-conversion`_, `-Wstring-conversion`_.
**Diagnostic text:**
@@ -2343,15 +2433,15 @@ Also controls `-Wbool-conversion`_, `-Wconstant-conversion`_, `-Wenum-conversion
Synonym for `-Wnull-conversion`_.
--Wcoreturn-without-coawait
---------------------------
+-Wcoroutine
+-----------
This diagnostic is enabled by default.
**Diagnostic text:**
-+--------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'co\_return' used in a function that uses neither 'co\_await' nor 'co\_yield'`|
-+--------------------------------------------------------------------------------------------------------------------+
++-----------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is required to declare the member 'unhandled\_exception()' when exceptions are enabled`|
++-----------------------------------------------------------------------------------------------------------------------------------------------------+
-Wcovered-switch-default
@@ -2390,6 +2480,10 @@ Some of the diagnostics controlled by this flag are enabled by default.
|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute parameter` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is negative and will be ignored`|
+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
++---------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`nvcc does not allow '\_\_`:placeholder:`A`:diagtext:`\_\_' to appear after '()' in lambdas`|
++---------------------------------------------------------------------------------------------------------------------------------+
+
+------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`ignored 'inline' attribute on kernel function` |nbsp| :placeholder:`A`|
+------------------------------------------------------------------------------------------------------------+
@@ -2558,7 +2652,7 @@ Some of the diagnostics controlled by this flag are enabled by default.
------------
Some of the diagnostics controlled by this flag are enabled by default.
-Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_, `-Wdeprecated-writable-strings`_.
+Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdeprecated-dynamic-exception-spec`_, `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_, `-Wdeprecated-writable-strings`_.
**Diagnostic text:**
@@ -2596,10 +2690,6 @@ Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdepre
|:warning:`warning:` |nbsp| :diagtext:`treating '`:placeholder:`A`:diagtext:`' input as '`:placeholder:`B`:diagtext:`' when in C++ mode, this behavior is deprecated`|
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-+--------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`dynamic exception specifications are deprecated`|
-+--------------------------------------------------------------------------------------+
-
+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`OpenCL version` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not support the option '`:placeholder:`B`:diagtext:`'`|
+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -2647,6 +2737,15 @@ This diagnostic is enabled by default.
+-------------------------------------------------------------------------------------------------------------------------------------+
+-Wdeprecated-dynamic-exception-spec
+-----------------------------------
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`dynamic exception specifications are deprecated`|
++--------------------------------------------------------------------------------------+
+
+
-Wdeprecated-implementations
----------------------------
**Diagnostic text:**
@@ -3089,6 +3188,17 @@ This diagnostic is enabled by default.
+-----------------------------------------------------------------------------------------------------------------------------------+
+-Wduplicate-protocol
+--------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`duplicate protocol definition of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is ignored`|
++-----------------------------------------------------------------------------------------------------------------------------+
+
+
-Wdynamic-class-memaccess
-------------------------
This diagnostic is enabled by default.
@@ -3108,6 +3218,19 @@ This diagnostic is enabled by default.
+---------------------------+-------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------+---------------------------------------------------------------------------------------------+-------------------------+
+-Wdynamic-exception-spec
+------------------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Also controls `-Wdeprecated-dynamic-exception-spec`_.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------+
+|:error:`error:` |nbsp| :diagtext:`ISO C++1z does not allow dynamic exception specifications`|
++--------------------------------------------------------------------------------------------+
+
+
-Weffc++
--------
Synonym for `-Wnon-virtual-dtor`_.
@@ -3328,7 +3451,13 @@ This diagnostic is enabled by default.
-------
Some of the diagnostics controlled by this flag are enabled by default.
-Controls `-Wignored-qualifiers`_, `-Winitializer-overrides`_, `-Wmissing-field-initializers`_, `-Wmissing-method-return-type`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_.
+Also controls `-Wignored-qualifiers`_, `-Winitializer-overrides`_, `-Wmissing-field-initializers`_, `-Wmissing-method-return-type`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_.
+
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`call to function without interrupt attribute could clobber interruptee's VFP registers`|
++-----------------------------------------------------------------------------------------------------------------------------+
-Wextra-qualification
@@ -3498,6 +3627,10 @@ Also controls `-Wformat-extra-args`_, `-Wformat-invalid-specifier`_, `-Wformat-s
**Diagnostic text:**
++-------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`using '%%P' format specifier without precision`|
++-------------------------------------------------------------------------------------+
+
+---------------------------+----------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| |+--------------------------------------------+| |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' should not be used as format arguments; add an explicit cast to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`instead`|
| ||:diagtext:`values of type` || |
@@ -3514,6 +3647,10 @@ Also controls `-Wformat-extra-args`_, `-Wformat-invalid-specifier`_, `-Wformat-s
| |+---------------------------+| |
+------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+
++----------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`using '`:placeholder:`A`:diagtext:`' format specifier annotation outside of os\_log()/os\_trace()`|
++----------------------------------------------------------------------------------------------------------------------------------------+
+
+-----------------------------------------------------------------------------+-----------------------------+
|:warning:`warning:` |nbsp| :diagtext:`invalid position specified for` |nbsp| |+---------------------------+|
| ||:diagtext:`field width` ||
@@ -3756,6 +3893,10 @@ Some of the diagnostics controlled by this flag are enabled by default.
**Diagnostic text:**
++--------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`'diagnose\_if' is a clang extension`|
++--------------------------------------------------------------------------+
+
+------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`'enable\_if' is a clang extension`|
+------------------------------------------------------------------------+
@@ -4268,6 +4409,8 @@ This diagnostic is enabled by default.
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`variables and functions` ||
| |+----------------------------------------------------------------------------------------------------------------+|
+| ||:diagtext:`functions and global variables` ||
+| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`functions, variables, and Objective-C interfaces` ||
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`functions and methods` ||
@@ -4280,6 +4423,8 @@ This diagnostic is enabled by default.
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`functions, methods, and parameters` ||
| |+----------------------------------------------------------------------------------------------------------------+|
+| ||:diagtext:`functions, methods, and global variables` ||
+| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`classes` ||
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`enums` ||
@@ -4326,7 +4471,7 @@ This diagnostic is enabled by default.
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`variables with static or thread storage duration` ||
| |+----------------------------------------------------------------------------------------------------------------+|
-| ||:diagtext:`functions and global variables` ||
+| ||:diagtext:`functions, methods, properties, and global variables` ||
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`structs, unions, and typedefs` ||
| |+----------------------------------------------------------------------------------------------------------------+|
@@ -4346,6 +4491,10 @@ This diagnostic is enabled by default.
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members`||
| |+----------------------------------------------------------------------------------------------------------------+|
+| ||:diagtext:`classes and enumerations` ||
+| |+----------------------------------------------------------------------------------------------------------------+|
+| ||:diagtext:`named declarations` ||
+| |+----------------------------------------------------------------------------------------------------------------+|
+------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -4516,10 +4665,27 @@ This diagnostic is enabled by default.
+--------------------------------------------------------------------------------------------------------+
+-Wignored-pragma-intrinsic
+--------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++------------------------------------------------------------------------------------------+------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not a recognized builtin`|+----------------------------------------------------------------------------+|
+| || ||
+| |+----------------------------------------------------------------------------+|
+| ||:diagtext:`; consider including <intrin.h> to access non-builtin intrinsics`||
+| |+----------------------------------------------------------------------------+|
++------------------------------------------------------------------------------------------+------------------------------------------------------------------------------+
+
+
-Wignored-pragmas
-----------------
This diagnostic is enabled by default.
+Also controls `-Wignored-pragma-intrinsic`_.
+
**Diagnostic text:**
+------------------------------------------------------------------------------+---------------------------+-----------------------+
@@ -4538,6 +4704,10 @@ This diagnostic is enabled by default.
| |+-------------------------+| |
+-----------------------------------------------------------------------------------+---------------------------+-----------------------+
++-----------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`OpenCL extension end directive mismatches begin directive - ignoring`|
++-----------------------------------------------------------------------------------------------------------+
+
+----------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`'#pragma comment` |nbsp| :placeholder:`A`:diagtext:`' ignored`|
+----------------------------------------------------------------------------------------------------+
@@ -4562,10 +4732,6 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`missing ':' or ')' after` |nbsp| :placeholder:`A` |nbsp| :diagtext:`- ignoring`|
+---------------------------------------------------------------------------------------------------------------------+
-+--------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`expected 'enable' or 'disable' - ignoring`|
-+--------------------------------------------------------------------------------+
-
+---------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`expected identifier in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`|
+---------------------------------------------------------------------------------------------------------------------+
@@ -4586,6 +4752,14 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`expected non-wide string literal in '#pragma` |nbsp| :placeholder:`A`:diagtext:`'`|
+------------------------------------------------------------------------------------------------------------------------+
++-------------------------------------------------------+---------------------------------------------------+------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`expected` |nbsp| |+-------------------------------------------------+| |nbsp| :diagtext:`- ignoring`|
+| ||:diagtext:`'enable', 'disable', 'begin' or 'end'`|| |
+| |+-------------------------------------------------+| |
+| ||:diagtext:`'disable'` || |
+| |+-------------------------------------------------+| |
++-------------------------------------------------------+---------------------------------------------------+------------------------------+
+
+-----------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`expected ')' or ',' in '#pragma` |nbsp| :placeholder:`A`:diagtext:`'`|
+-----------------------------------------------------------------------------------------------------------+
@@ -4610,18 +4784,14 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`extra tokens at end of '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`|
+---------------------------------------------------------------------------------------------------------------------+
++----------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`incorrect use of #pragma clang force\_cuda\_host\_device begin\|end`|
++----------------------------------------------------------------------------------------------------------+
+
+-------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`'#pragma init\_seg' is only supported when targeting a Microsoft environment`|
+-------------------------------------------------------------------------------------------------------------------+
-+------------------------------------------------------------------------------------------+------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not a recognized builtin`|+----------------------------------------------------------------------------+|
-| || ||
-| |+----------------------------------------------------------------------------+|
-| ||:diagtext:`; consider including <intrin.h> to access non-builtin intrinsics`||
-| |+----------------------------------------------------------------------------+|
-+------------------------------------------------------------------------------------------+------------------------------------------------------------------------------+
-
+-----------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`unknown action for '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`|
+-----------------------------------------------------------------------------------------------------------------+
@@ -4894,6 +5064,25 @@ This diagnostic is enabled by default.
+----------------------------------------------------------------------------+
+-Wincompatible-exception-spec
+-----------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------+----------------------+--------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`exception specifications of` |nbsp| |+--------------------+| |nbsp| :diagtext:`types differ`|
+| ||:diagtext:`return` || |
+| |+--------------------+| |
+| ||:diagtext:`argument`|| |
+| |+--------------------+| |
++--------------------------------------------------------------------------+----------------------+--------------------------------+
+
++-----------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`target exception specification is not superset of source`|
++-----------------------------------------------------------------------------------------------+
+
+
-Wincompatible-function-pointer-types
-------------------------------------
This diagnostic is enabled by default.
@@ -5081,6 +5270,15 @@ This diagnostic is enabled by default.
+------------------------------------------------------------------------------------------------------------------------------------+
+-Winconsistent-missing-destructor-override
+------------------------------------------
+**Diagnostic text:**
+
++------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`overrides a destructor but is not marked 'override'`|
++------------------------------------------------------------------------------------------------------------------+
+
+
-Winconsistent-missing-override
-------------------------------
This diagnostic is enabled by default.
@@ -5133,6 +5331,21 @@ This diagnostic is enabled by default.
+---------------------------------------------------------------------------------------------------------------------------------------+
+-Winjected-class-name
+---------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+--------------------------------------------------------------+------------------------+---------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ISO C++ specifies that qualified reference to` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is a constructor name rather than a` |nbsp| |+-------------------------+| |nbsp| :diagtext:`in this context, despite preceding` |nbsp| |+----------------------+| |nbsp| :diagtext:`keyword`|
+| ||:diagtext:`template name`|| ||:diagtext:`'typename'`|| |
+| |+-------------------------+| |+----------------------+| |
+| ||:diagtext:`type` || ||:diagtext:`'template'`|| |
+| |+-------------------------+| |+----------------------+| |
++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+--------------------------------------------------------------+------------------------+---------------------------+
+
+
-Winline
--------
This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
@@ -5354,6 +5567,21 @@ Some of the diagnostics controlled by this flag are enabled by default.
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-Winvalid-partial-specialization
+--------------------------------
+This diagnostic is an error by default, but the flag ``-Wno-invalid-partial-specialization`` can be used to disable the error.
+
+**Diagnostic text:**
+
++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------+
+|:error:`error:` |nbsp| |+--------------------+| |nbsp| :diagtext:`template partial specialization is not more specialized than the primary template`|
+| ||:diagtext:`class` || |
+| |+--------------------+| |
+| ||:diagtext:`variable`|| |
+| |+--------------------+| |
++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------+
+
+
-Winvalid-pch
-------------
This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
@@ -5475,14 +5703,7 @@ This diagnostic is enabled by default.
-Wliblto
--------
-This diagnostic is enabled by default.
-
-**Diagnostic text:**
-
-+-------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`libLTO.dylib relative to clang installed dir not found; using 'ld' default search path instead`|
-+-------------------------------------------------------------------------------------------------------------------------------------+
-
+This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
-Wliteral-conversion
--------------------
@@ -5529,9 +5750,13 @@ This diagnostic is enabled by default.
**Diagnostic text:**
-+-----------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`logical not is only applied to the left hand side of this comparison`|
-+-----------------------------------------------------------------------------------------------------------+
++--------------------------------------------------------------------------------------------------------+------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`logical not is only applied to the left hand side of this` |nbsp| |+----------------------------+|
+| ||:diagtext:`comparison` ||
+| |+----------------------------+|
+| ||:diagtext:`bitwise operator`||
+| |+----------------------------+|
++--------------------------------------------------------------------------------------------------------+------------------------------+
-Wlogical-op-parentheses
@@ -5598,6 +5823,10 @@ Some of the diagnostics controlled by this flag are enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`variable named 'main' with external linkage has undefined behavior`|
+---------------------------------------------------------------------------------------------------------+
++------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`bool literal returned from 'main'`|
++------------------------------------------------------------------------+
+
+---------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`'main' should not be declared static`|
+---------------------------------------------------------------------------+
@@ -5636,6 +5865,21 @@ This diagnostic is enabled by default.
+--------------------------------------------------------------------------------+
+-Wmax-unsigned-zero
+-------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------+---------------------------------------+------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`taking the max of` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`is always equal to the other value`|
+| ||:diagtext:`a value and unsigned zero`|| |
+| |+-------------------------------------+| |
+| ||:diagtext:`unsigned zero and a value`|| |
+| |+-------------------------------------+| |
++----------------------------------------------------------------+---------------------------------------+------------------------------------------------------+
+
+
-Wmemsize-comparison
--------------------
This diagnostic is enabled by default.
@@ -6269,6 +6513,14 @@ This diagnostic is enabled by default.
|:remark:`remark:` |nbsp| :diagtext:`finished building module '`:placeholder:`A`:diagtext:`'`|
+--------------------------------------------------------------------------------------------+
++-----------------------------------------------------------------------------------------------------------------------------------+
+|:remark:`remark:` |nbsp| :diagtext:`could not acquire lock file for module '`:placeholder:`A`:diagtext:`':` |nbsp| :placeholder:`B`|
++-----------------------------------------------------------------------------------------------------------------------------------+
+
++---------------------------------------------------------------------------------------------------------------------+
+|:remark:`remark:` |nbsp| :diagtext:`timed out waiting to acquire lock file for module '`:placeholder:`A`:diagtext:`'`|
++---------------------------------------------------------------------------------------------------------------------+
+
-Wmodule-conflict
-----------------
@@ -6280,6 +6532,10 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`module '`:placeholder:`A`:diagtext:`' conflicts with already-imported module '`:placeholder:`B`:diagtext:`':` |nbsp| :placeholder:`C`|
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`module file '`:placeholder:`A`:diagtext:`' was validated as a system module and is now being imported as a non-system module; any difference in diagnostic options will be ignored`|
++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
-Wmodule-file-config-mismatch
-----------------------------
@@ -6340,7 +6596,7 @@ This diagnostic is an error by default, but the flag ``-Wno-modules-import-neste
------
Some of the diagnostics controlled by this flag are enabled by default.
-Controls `-Wcast-of-sel-type`_, `-Wchar-subscripts`_, `-Wcomment`_, `-Wdelete-non-virtual-dtor`_, `-Wextern-c-compat`_, `-Wfor-loop-analysis`_, `-Wformat`_, `-Wimplicit`_, `-Winfinite-recursion`_, `-Wmismatched-tags`_, `-Wmissing-braces`_, `-Wmove`_, `-Wmultichar`_, `-Wobjc-designated-initializers`_, `-Wobjc-missing-super-calls`_, `-Woverloaded-virtual`_, `-Wprivate-extern`_, `-Wreorder`_, `-Wreturn-type`_, `-Wself-assign`_, `-Wself-move`_, `-Wsizeof-array-argument`_, `-Wsizeof-array-decay`_, `-Wstring-plus-int`_, `-Wtrigraphs`_, `-Wuninitialized`_, `-Wunknown-pragmas`_, `-Wunused`_, `-Wvolatile-register-var`_.
+Controls `-Wcast-of-sel-type`_, `-Wchar-subscripts`_, `-Wcomment`_, `-Wdelete-non-virtual-dtor`_, `-Wextern-c-compat`_, `-Wfor-loop-analysis`_, `-Wformat`_, `-Wimplicit`_, `-Winfinite-recursion`_, `-Wmismatched-tags`_, `-Wmissing-braces`_, `-Wmove`_, `-Wmultichar`_, `-Wobjc-designated-initializers`_, `-Wobjc-missing-super-calls`_, `-Woverloaded-virtual`_, `-Wprivate-extern`_, `-Wreorder`_, `-Wreturn-type`_, `-Wself-assign`_, `-Wself-move`_, `-Wsizeof-array-argument`_, `-Wsizeof-array-decay`_, `-Wstring-plus-int`_, `-Wtrigraphs`_, `-Wuninitialized`_, `-Wunknown-pragmas`_, `-Wunused`_, `-Wuser-defined-warnings`_, `-Wvolatile-register-var`_.
-Wmove
@@ -6353,6 +6609,17 @@ Controls `-Wpessimizing-move`_, `-Wredundant-move`_, `-Wself-move`_.
Synonym for `-Wmicrosoft-include`_.
+-Wmsvc-not-found
+----------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unable to find a Visual Studio installation; try running Clang from a developer command prompt`|
++-------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wmultichar
-----------
This diagnostic is enabled by default.
@@ -6447,9 +6714,9 @@ This diagnostic is enabled by default.
-----------------------------------------
**Diagnostic text:**
-+---------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`include of non-modular header inside framework module '`:placeholder:`A`:diagtext:`'`|
-+---------------------------------------------------------------------------------------------------------------------------+
++-----------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`include of non-modular header inside framework module '`:placeholder:`A`:diagtext:`': '`:placeholder:`B`:diagtext:`'`|
++-----------------------------------------------------------------------------------------------------------------------------------------------------------+
-Wnon-modular-include-in-module
@@ -6458,9 +6725,9 @@ Also controls `-Wnon-modular-include-in-framework-module`_.
**Diagnostic text:**
-+-----------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`include of non-modular header inside module '`:placeholder:`A`:diagtext:`'`|
-+-----------------------------------------------------------------------------------------------------------------+
++-------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`include of non-modular header inside module '`:placeholder:`A`:diagtext:`': '`:placeholder:`B`:diagtext:`'`|
++-------------------------------------------------------------------------------------------------------------------------------------------------+
-Wnon-pod-varargs
@@ -6668,6 +6935,8 @@ This diagnostic is enabled by default.
--------------------------
This diagnostic is enabled by default.
+Also controls `-Wnullability-completeness-on-arrays`_.
+
**Diagnostic text:**
+---------------------------+----------------------------+-----------------------------------------------------------------------------------------------------------+
@@ -6681,6 +6950,17 @@ This diagnostic is enabled by default.
+---------------------------+----------------------------+-----------------------------------------------------------------------------------------------------------+
+-Wnullability-completeness-on-arrays
+------------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`array parameter is missing a nullability type specifier (\_Nonnull, \_Nullable, or \_Null\_unspecified)`|
++----------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wnullability-declspec
----------------------
This diagnostic is an error by default, but the flag ``-Wno-nullability-declspec`` can be used to disable the error.
@@ -6711,6 +6991,21 @@ This diagnostic is an error by default, but the flag ``-Wno-nullability-declspec
+---------------------------------------------------------------------------------------------------------------------------------+
+-Wnullability-inferred-on-nested-type
+-------------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------+-----------------------+---------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`inferring '\_Nonnull' for pointer type within` |nbsp| |+---------------------+| |nbsp| :diagtext:`is deprecated`|
+| ||:diagtext:`array` || |
+| |+---------------------+| |
+| ||:diagtext:`reference`|| |
+| |+---------------------+| |
++--------------------------------------------------------------------------------------------+-----------------------+---------------------------------+
+
+
-Wnullable-to-nonnull-conversion
--------------------------------
**Diagnostic text:**
@@ -7113,6 +7408,23 @@ This diagnostic is enabled by default.
+-------------------------------------------------------------------------------------------------------------------------+
+-Wobjc-unsafe-perform-selector
+------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------+--------------------+------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is incompatible with selectors that return a` |nbsp| |+------------------+| |nbsp| :diagtext:`type`|
+| ||:diagtext:`struct`|| |
+| |+------------------+| |
+| ||:diagtext:`union` || |
+| |+------------------+| |
+| ||:diagtext:`vector`|| |
+| |+------------------+| |
++-------------------------------------------------------------------------------------------------------------------+--------------------+------------------------+
+
+
-Wodr
-----
This diagnostic is enabled by default.
@@ -7188,6 +7500,10 @@ This diagnostic is enabled by default.
**Diagnostic text:**
++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`The OpenMP offloading target '`:placeholder:`A`:diagtext:`' is similar to target '`:placeholder:`B`:diagtext:`' already specified - will be ignored.`|
++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+-----------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`declaration is not declared in any declare target region`|
+-----------------------------------------------------------------------------------------------+
@@ -7468,6 +7784,10 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
|:warning:`warning:` |nbsp| :diagtext:`'enable\_if' is a clang extension`|
+------------------------------------------------------------------------+
++--------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`'diagnose\_if' is a clang extension`|
++--------------------------------------------------------------------------+
+
+--------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`designated initializers are a C99 feature`|
+--------------------------------------------------------------------------------+
@@ -8040,6 +8360,17 @@ This diagnostic is an error by default, but the flag ``-Wno-private-header`` can
+----------------------------------------------------------------------------------------------------------------+
+-Wprivate-module
+----------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`top-level module '`:placeholder:`A`:diagtext:`' in private module map, expected a submodule of '`:placeholder:`B`:diagtext:`'`|
++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wprofile-instr-out-of-date
---------------------------
This diagnostic is enabled by default.
@@ -8364,6 +8695,10 @@ Also controls `-Wreturn-type-c-linkage`_.
| |+--------------------+| |
+---------------------------------------------------+----------------------+-----------------------------------------------------------------+
++--------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void coroutine`|
++--------------------------------------------------------------------------------+
+
+-------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void function`|
+-------------------------------------------------------------------------------+
@@ -8372,6 +8707,10 @@ Also controls `-Wreturn-type-c-linkage`_.
|:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void lambda`|
+-----------------------------------------------------------------------------+
++----------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`control may reach end of non-void coroutine`|
++----------------------------------------------------------------------------------+
+
+---------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`control may reach end of non-void function`|
+---------------------------------------------------------------------------------+
@@ -8586,6 +8925,14 @@ Also controls `-Wshadow-field-in-constructor-modified`_, `-Wshadow-ivar`_.
| |||:diagtext:`field of` |nbsp| :placeholder:`C`| ||
| ||+--------------------------------------------+ ||
| |+-----------------------------------------------------------+|
+| ||+----------------------------------------------+ ||
+| |||:diagtext:`typedef in` |nbsp| :placeholder:`C`| ||
+| ||+----------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
+| ||+-------------------------------------------------+ ||
+| |||:diagtext:`type alias in` |nbsp| :placeholder:`C`| ||
+| ||+-------------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
+--------------------------------------------------------------------+-------------------------------------------------------------+
@@ -8593,7 +8940,16 @@ Also controls `-Wshadow-field-in-constructor-modified`_, `-Wshadow-ivar`_.
------------
Some of the diagnostics controlled by this flag are enabled by default.
-Controls `-Wshadow`_, `-Wshadow-field-in-constructor`_.
+Controls `-Wshadow`_, `-Wshadow-field`_, `-Wshadow-field-in-constructor`_, `-Wshadow-uncaptured-local`_.
+
+
+-Wshadow-field
+--------------
+**Diagnostic text:**
+
++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`non-static data member '`:placeholder:`A`:diagtext:`' of '`:placeholder:`B`:diagtext:`' shadows member inherited from type '`:placeholder:`C`:diagtext:`'`|
++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-Wshadow-field-in-constructor
@@ -8627,6 +8983,37 @@ This diagnostic is enabled by default.
+------------------------------------------------------------------------------------------------------------------------------+
+-Wshadow-uncaptured-local
+-------------------------
+**Diagnostic text:**
+
++--------------------------------------------------------------------+-------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`declaration shadows a` |nbsp| |+-----------------------------------------------------------+|
+| ||:diagtext:`local variable` ||
+| |+-----------------------------------------------------------+|
+| ||+-----------------------------------------------+ ||
+| |||:diagtext:`variable in` |nbsp| :placeholder:`C`| ||
+| ||+-----------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
+| ||+---------------------------------------------------------+||
+| |||:diagtext:`static data member of` |nbsp| :placeholder:`C`|||
+| ||+---------------------------------------------------------+||
+| |+-----------------------------------------------------------+|
+| ||+--------------------------------------------+ ||
+| |||:diagtext:`field of` |nbsp| :placeholder:`C`| ||
+| ||+--------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
+| ||+----------------------------------------------+ ||
+| |||:diagtext:`typedef in` |nbsp| :placeholder:`C`| ||
+| ||+----------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
+| ||+-------------------------------------------------+ ||
+| |||:diagtext:`type alias in` |nbsp| :placeholder:`C`| ||
+| ||+-------------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
++--------------------------------------------------------------------+-------------------------------------------------------------+
+
+
-Wshift-count-negative
----------------------
This diagnostic is enabled by default.
@@ -8726,6 +9113,15 @@ This diagnostic is enabled by default.
------------
This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
+-Wsigned-enum-bitfield
+----------------------
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`enums in the Microsoft ABI are signed integers by default; consider giving the enum` |nbsp| :placeholder:`A` |nbsp| :diagtext:`an unsigned underlying type to make this code portable`|
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wsizeof-array-argument
-----------------------
This diagnostic is enabled by default.
@@ -8767,6 +9163,17 @@ This diagnostic is enabled by default.
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------+---------------------------------------------------------------------------------------+
+-Wslash-u-filename
+------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`'/U`:placeholder:`A`:diagtext:`' treated as the '/U' option`|
++--------------------------------------------------------------------------------------------------+
+
+
-Wsometimes-uninitialized
-------------------------
**Diagnostic text:**
@@ -8957,7 +9364,29 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
-Wstrict-prototypes
-------------------
-This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
+**Diagnostic text:**
+
++---------------------------------------------------+--------------------------------------------------------------+-------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`this` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`a prototype`|
+| ||:diagtext:`function declaration is not` || |
+| |+------------------------------------------------------------+| |
+| ||:diagtext:`old-style function definition is not preceded by`|| |
+| |+------------------------------------------------------------+| |
++---------------------------------------------------+--------------------------------------------------------------+-------------------------------+
+
+
+-Wstrict-prototypes
+-------------------
+**Diagnostic text:**
+
++---------------------------------------------------+--------------------------------------------------------------+-------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`this` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`a prototype`|
+| ||:diagtext:`function declaration is not` || |
+| |+------------------------------------------------------------+| |
+| ||:diagtext:`old-style function definition is not preceded by`|| |
+| |+------------------------------------------------------------+| |
++---------------------------------------------------+--------------------------------------------------------------+-------------------------------+
+
-Wstrict-selector-match
-----------------------
@@ -9587,6 +10016,17 @@ This diagnostic is enabled by default.
+-------------------------------------------------------------------------------------------------------------------------------------+
+-Wunable-to-open-stats-file
+---------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unable to open statistics output file '`:placeholder:`A`:diagtext:`': '`:placeholder:`B`:diagtext:`'`|
++-------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wunavailable-declarations
--------------------------
This diagnostic is enabled by default.
@@ -10113,11 +10553,26 @@ This diagnostic is enabled by default.
+------------------------------------------------------------------------------------------------------+
+-Wunusable-partial-specialization
+---------------------------------
+This diagnostic is an error by default, but the flag ``-Wno-unusable-partial-specialization`` can be used to disable the error.
+
+**Diagnostic text:**
+
++-----------------------+----------------------+--------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------+
+|:error:`error:` |nbsp| |+--------------------+| |nbsp| :diagtext:`template partial specialization contains` |nbsp| |+--------------------------------+| |nbsp| :diagtext:`that cannot be deduced; this partial specialization will never be used`|
+| ||:diagtext:`class` || ||:diagtext:`a template parameter`|| |
+| |+--------------------+| |+--------------------------------+| |
+| ||:diagtext:`variable`|| ||:diagtext:`template parameters` || |
+| |+--------------------+| |+--------------------------------+| |
++-----------------------+----------------------+--------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------+
+
+
-Wunused
--------
Some of the diagnostics controlled by this flag are enabled by default.
-Controls `-Wunused-argument`_, `-Wunused-function`_, `-Wunused-label`_, `-Wunused-local-typedef`_, `-Wunused-private-field`_, `-Wunused-property-ivar`_, `-Wunused-value`_, `-Wunused-variable`_.
+Controls `-Wunused-argument`_, `-Wunused-function`_, `-Wunused-label`_, `-Wunused-lambda-capture`_, `-Wunused-local-typedef`_, `-Wunused-private-field`_, `-Wunused-property-ivar`_, `-Wunused-value`_, `-Wunused-variable`_.
-Wunused-argument
@@ -10237,6 +10692,19 @@ This diagnostic is enabled by default.
+---------------------------------------------------------------------------+
+-Wunused-lambda-capture
+-----------------------
+**Diagnostic text:**
+
++---------------------------------------------------------------------------------------------------------------+--------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`lambda capture` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not` |nbsp| |+------------------------------------------------+|
+| ||:diagtext:`used` ||
+| |+------------------------------------------------+|
+| ||:diagtext:`required to be captured for this use`||
+| |+------------------------------------------------+|
++---------------------------------------------------------------------------------------------------------------+--------------------------------------------------+
+
+
-Wunused-local-typedef
----------------------
**Diagnostic text:**
@@ -10384,6 +10852,15 @@ This diagnostic is enabled by default.
+--------------------------------------------------------------------------------------------------------+----------------------------------------------------+
+-Wuser-defined-warnings
+-----------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
+The text of this diagnostic is not controlled by Clang.
+
+
-Wvarargs
---------
This diagnostic is enabled by default.
@@ -10422,6 +10899,17 @@ This diagnostic is enabled by default.
+------------------------------------------------------------------------+
+-Wvec-elem-size
+---------------
+This diagnostic is an error by default, but the flag ``-Wno-vec-elem-size`` can be used to disable the error.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:error:`error:` |nbsp| :diagtext:`vector operands do not have the same elements sizes (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`)`|
++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wvector-conversion
-------------------
**Diagnostic text:**
diff --git a/docs/ExternalClangExamples.rst b/docs/ExternalClangExamples.rst
index e6076a5be6d1..b92fa3fcc068 100644
--- a/docs/ExternalClangExamples.rst
+++ b/docs/ExternalClangExamples.rst
@@ -85,3 +85,16 @@ List of projects and tools
errors, fixit hints). See also `<http://l.rw.rw/clang_plugin>`_ for
step-by-step instructions."
+`<https://phabricator.kde.org/source/clazy>`_
+ "clazy is a compiler plugin which allows clang to understand Qt semantics.
+ You get more than 50 Qt related compiler warnings, ranging from unneeded
+ memory allocations to misusage of API, including fix-its for automatic
+ refactoring."
+
+`<https://gerrit.libreoffice.org/gitweb?p=core.git;a=blob_plain;f=compilerplugins/README;hb=HEAD>`_
+ "LibreOffice uses a Clang plugin infrastructure to check during the build
+ various things, some more, some less specific to the LibreOffice source code.
+ There are currently around 50 such checkers, from flagging C-style casts and
+ uses of reserved identifiers to ensuring that code adheres to lifecycle
+ protocols for certain LibreOffice-specific classes. They may serve as
+ examples for writing RecursiveASTVisitor-based plugins."
diff --git a/docs/LTOVisibility.rst b/docs/LTOVisibility.rst
index 67367f3d635e..e1372d667a1a 100644
--- a/docs/LTOVisibility.rst
+++ b/docs/LTOVisibility.rst
@@ -10,15 +10,16 @@ using link-time optimization; in the case where LTO is not being used, the
linkage unit's LTO unit is empty. Each linkage unit has only a single LTO unit.
The LTO visibility of a class is used by the compiler to determine which
-classes the virtual function call optimization and control flow integrity
-features apply to. These features use whole-program information, so they
-require the entire class hierarchy to be visible in order to work correctly.
-
-If any translation unit in the program uses either of the virtual function
-call optimization or control flow integrity features, it is effectively an
-ODR violation to define a class with hidden LTO visibility in multiple linkage
+classes the whole-program devirtualization (``-fwhole-program-vtables``) and
+control flow integrity (``-fsanitize=cfi-vcall``) features apply to. These
+features use whole-program information, so they require the entire class
+hierarchy to be visible in order to work correctly.
+
+If any translation unit in the program uses either of the whole-program
+devirtualization or control flow integrity features, it is effectively an ODR
+violation to define a class with hidden LTO visibility in multiple linkage
units. A class with public LTO visibility may be defined in multiple linkage
-units, but the tradeoff is that the virtual function call optimization and
+units, but the tradeoff is that the whole-program devirtualization and
control flow integrity features can only be applied to classes with hidden LTO
visibility. A class's LTO visibility is treated as an ODR-relevant property
of its definition, so it must be consistent between translation units.
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 885ad579ba72..a8fb4623b637 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -356,7 +356,7 @@ is:
Query for this feature with ``__has_extension(attribute_ext_vector_type)``.
-Giving ``-faltivec`` option to clang enables support for AltiVec vector syntax
+Giving ``-maltivec`` option to clang enables support for AltiVec vector syntax
and functions. For example:
.. code-block:: c++
@@ -993,6 +993,7 @@ The following type trait primitives are supported by Clang:
* ``__has_trivial_destructor`` (GNU, Microsoft)
* ``__has_virtual_destructor`` (GNU, Microsoft)
* ``__is_abstract`` (GNU, Microsoft)
+* ``__is_aggregate`` (GNU, Microsoft)
* ``__is_base_of`` (GNU, Microsoft)
* ``__is_class`` (GNU, Microsoft)
* ``__is_convertible_to`` (Microsoft)
@@ -1780,7 +1781,7 @@ String builtins
---------------
Clang provides constant expression evaluation support for builtins forms of
-the following functions from the C standard library ``<strings.h>`` header:
+the following functions from the C standard library ``<string.h>`` header:
* ``memchr``
* ``memcmp``
@@ -2312,3 +2313,36 @@ For example, the hint ``vectorize_width(4)`` is ignored if the loop is not
proven safe to vectorize. To identify and diagnose optimization issues use
`-Rpass`, `-Rpass-missed`, and `-Rpass-analysis` command line options. See the
user guide for details.
+
+Extensions to specify floating-point flags
+====================================================
+
+The ``#pragma clang fp`` pragma allows floating-point options to be specified
+for a section of the source code. This pragma can only appear at file scope or
+at the start of a compound statement (excluding comments). When using within a
+compound statement, the pragma is active within the scope of the compound
+statement.
+
+Currently, only FP contraction can be controlled with the pragma. ``#pragma
+clang fp contract`` specifies whether the compiler should contract a multiply
+and an addition (or subtraction) into a fused FMA operation when supported by
+the target.
+
+The pragma can take three values: ``on``, ``fast`` and ``off``. The ``on``
+option is identical to using ``#pragma STDC FP_CONTRACT(ON)`` and it allows
+fusion as specified the language standard. The ``fast`` option allows fusiong
+in cases when the language standard does not make this possible (e.g. across
+statements in C)
+
+.. code-block:: c++
+
+ for(...) {
+ #pragma clang fp contract(fast)
+ a = b[i] * c[i];
+ d[i] += a;
+ }
+
+
+The pragma can also be used with ``off`` which turns FP contraction off for a
+section of the code. This can be useful when fast contraction is otherwise
+enabled for the translation unit with the ``-ffp-contract=fast`` flag.
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index 4ee953f1838e..736e1dfcabcf 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -337,6 +337,15 @@ nonTypeTemplateParmDecl()
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcCategoryDecl0')"><a name="objcCategoryDecl0Anchor">objcCategoryDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCCategoryDecl.html">ObjCCategoryDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="objcCategoryDecl0"><pre>Matches Objective-C category declarations.
+
+Example matches Foo (Additions)
+ @interface Foo (Additions)
+ @end
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcInterfaceDecl0')"><a name="objcInterfaceDecl0Anchor">objcInterfaceDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcInterfaceDecl0"><pre>Matches Objective-C interface declarations.
@@ -346,6 +355,50 @@ Example matches Foo
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcIvarDecl0')"><a name="objcIvarDecl0Anchor">objcIvarDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCIvarDecl.html">ObjCIvarDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="objcIvarDecl0"><pre>Matches Objective-C instance variable declarations.
+
+Example matches _enabled
+ @implementation Foo {
+ BOOL _enabled;
+ }
+ @end
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcMethodDecl0')"><a name="objcMethodDecl0Anchor">objcMethodDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="objcMethodDecl0"><pre>Matches Objective-C method declarations.
+
+Example matches both declaration and definition of -[Foo method]
+ @interface Foo
+ - (void)method;
+ @end
+
+ @implementation Foo
+ - (void)method {}
+ @end
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcPropertyDecl0')"><a name="objcPropertyDecl0Anchor">objcPropertyDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCPropertyDecl.html">ObjCPropertyDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="objcPropertyDecl0"><pre>Matches Objective-C property declarations.
+
+Example matches enabled
+ @interface Foo
+ @property BOOL enabled;
+ @end
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcProtocolDecl0')"><a name="objcProtocolDecl0Anchor">objcProtocolDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCProtocolDecl.html">ObjCProtocolDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="objcProtocolDecl0"><pre>Matches Objective-C protocol declarations.
+
+Example matches FooDelegate
+ @protocol FooDelegate
+ @end
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('parmVarDecl0')"><a name="parmVarDecl0Anchor">parmVarDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="parmVarDecl0"><pre>Matches parameter variable declarations.
@@ -416,6 +469,15 @@ typeAliasDecl()
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('typeAliasTemplateDecl0')"><a name="typeAliasTemplateDecl0Anchor">typeAliasTemplateDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeAliasTemplateDecl.html">TypeAliasTemplateDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="typeAliasTemplateDecl0"><pre>Matches type alias template declarations.
+
+typeAliasTemplateDecl() matches
+ template &lt;typename T&gt;
+ using Y = X&lt;T&gt;;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('typedefDecl0')"><a name="typedefDecl0Anchor">typedefDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefDecl.html">TypedefDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="typedefDecl0"><pre>Matches typedef declarations.
@@ -5419,7 +5481,7 @@ alignof.
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('forFunction0')"><a name="forFunction0Anchor">forFunction</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="forFunction0"><pre>Matches declaration of the function the statemenet belongs to
+<tr><td colspan="4" class="doc" id="forFunction0"><pre>Matches declaration of the function the statement belongs to
Given:
F&amp; operator=(const F&amp; o) {
diff --git a/docs/Modules.rst b/docs/Modules.rst
index 141d3b85753f..2b1bde2fedc1 100644
--- a/docs/Modules.rst
+++ b/docs/Modules.rst
@@ -360,6 +360,7 @@ The ``framework`` qualifier specifies that this module corresponds to a Darwin-s
Name.framework/
Modules/module.modulemap Module map for the framework
Headers/ Subdirectory containing framework headers
+ PrivateHeaders/ Subdirectory containing framework private headers
Frameworks/ Subdirectory containing embedded frameworks
Resources/ Subdirectory containing additional resources
Name Symbolic link to the shared library for the framework
@@ -842,6 +843,16 @@ would be available when ``Foo_Private.h`` is available, making it
easier to split a library's public and private APIs along header
boundaries.
+When writing a private module as part of a *framework*, it's recommended that:
+
+* Headers for this module are present in the ``PrivateHeaders``
+ framework subdirectory.
+* The private module is defined as a *submodule* of the public framework (if
+ there's one), similar to how ``Foo.Private`` is defined in the example above.
+* The ``explicit`` keyword should be used to guarantee that its content will
+ only be available when the submodule itself is explicitly named (through a
+ ``@import`` for example).
+
Modularizing a Platform
=======================
To get any benefit out of modules, one needs to introduce module maps for software libraries starting at the bottom of the stack. This typically means introducing a module map covering the operating system's headers and the C standard library headers (in ``/usr/include``, for a Unix system).
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 3278bcc03381..f7e31e5c98d5 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -1,6 +1,6 @@
-=========================
-Clang 4.0.0 Release Notes
-=========================
+=======================================
+Clang 5.0.0 (In-Progress) Release Notes
+=======================================
.. contents::
:local:
@@ -8,11 +8,17 @@ Clang 4.0.0 Release Notes
Written by the `LLVM Team <http://llvm.org/>`_
+.. warning::
+
+ These are in-progress notes for the upcoming Clang 5 release.
+ Release notes for previous releases can be found on
+ `the Download Page <http://releases.llvm.org/download.html>`_.
+
Introduction
============
-This document contains the release notes for the Clang C/C++/Objective-C/OpenCL
-frontend, part of the LLVM Compiler Infrastructure, release 4.0.0. Here we
+This document contains the release notes for the Clang C/C++/Objective-C
+frontend, part of the LLVM Compiler Infrastructure, release 5.0.0. Here we
describe the status of Clang in some detail, including major
improvements from the previous release and new feature work. For the
general LLVM release notes, see `the LLVM
@@ -25,7 +31,12 @@ the latest release, please check out the main please see the `Clang Web
Site <http://clang.llvm.org>`_ or the `LLVM Web
Site <http://llvm.org>`_.
-What's New in Clang 4.0.0?
+Note that if you are reading this file from a Subversion checkout or the
+main Clang web page, this document applies to the *next* release, not
+the current one. To see the release notes for a specific release, please
+see the `releases page <http://llvm.org/releases/>`_.
+
+What's New in Clang 5.0.0?
==========================
Some of the major new features and improvements to Clang are listed
@@ -36,147 +47,165 @@ sections with improvements to Clang's support for those languages.
Major New Features
------------------
-- The `diagnose_if <AttributeReference.html#diagnose-if>`_ attribute has been
- added to clang. This attribute allows
- clang to emit a warning or error if a function call meets one or more
- user-specified conditions.
-
-- Enhanced devirtualization with
- `-fstrict-vtable-pointers <UsersManual.html#cmdoption-fstrict-vtable-pointers>`_.
- Clang devirtualizes across different basic blocks, like loops:
-
- .. code-block:: c++
-
- struct A {
- virtual void foo();
- };
- void indirect(A &a, int n) {
- for (int i = 0 ; i < n; i++)
- a.foo();
- }
- void test(int n) {
- A a;
- indirect(a, n);
- }
-
-
-Improvements to ThinLTO (-flto=thin)
-------------------------------------
-- Integration with profile data (PGO). When available, profile data enables
- more accurate function importing decisions, as well as cross-module indirect
- call promotion.
-- Significant build-time and binary-size improvements when compiling with debug
- info (``-g``).
+- ...
+
+Improvements to Clang's diagnostics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- -Wunused-lambda-capture warns when a variable explicitly captured
+ by a lambda is not used in the body of the lambda.
New Compiler Flags
------------------
-- The option ``-Og`` has been added to optimize the debugging experience.
- For now, this option is exactly the same as ``-O1``. However, in the future,
- some other optimizations might be enabled or disabled.
+The option ....
+
+New Pragmas in Clang
+-----------------------
+
+Clang now supports the ...
+
+
+Attribute Changes in Clang
+--------------------------
+
+- ...
+
+Windows Support
+---------------
+
+Clang's support for building native Windows programs ...
+
+
+C Language Changes in Clang
+---------------------------
+
+- ...
-- The option ``-MJ`` has been added to simplify adding JSON compilation
- database output into existing build systems.
+...
+C11 Feature Support
+^^^^^^^^^^^^^^^^^^^
+
+...
+
+C++ Language Changes in Clang
+-----------------------------
+
+...
+
+C++1z Feature Support
+^^^^^^^^^^^^^^^^^^^^^
+
+...
+
+Objective-C Language Changes in Clang
+-------------------------------------
+
+...
OpenCL C Language Changes in Clang
----------------------------------
-**The following bugs in the OpenCL header have been fixed:**
+...
+
+OpenMP Support in Clang
+----------------------------------
+
+...
-* Added missing ``overloadable`` and ``convergent`` attributes.
-* Removed some erroneous extra ``native_*`` functions.
+Internal API Changes
+--------------------
-**The following bugs in the generation of metadata have been fixed:**
+These are major API changes that have happened since the 4.0.0 release of
+Clang. If upgrading an external codebase that uses Clang as a library,
+this section should help get you past the largest hurdles of upgrading.
-* Corrected the SPIR version depending on the OpenCL version.
-* Source level address spaces are taken from the SPIR specification.
-* Image types now contain no access qualifier.
+- ...
-**The following bugs in the AMD target have been fixed:**
+AST Matchers
+------------
-* Corrected the bitwidth of ``size_t`` and NULL pointer value with respect to
- address spaces.
-* Added ``cl_khr_subgroups``, ``cl_amd_media_ops`` and ``cl_amd_media_ops2``
- extensions.
-* Added ``cl-denorms-are-zero`` support.
-* Changed address spaces for image objects to be ``constant``.
-* Added little-endian.
+...
-**The following bugs in OpenCL 2.0 have been fixed:**
-* Fixed pipe builtin function return type, added extra argument to generated
- IR intrinsics to propagate size and alignment information of the pipe packed
- type.
-* Improved pipe type to accommodate access qualifiers.
-* Added correct address space to the ObjC block generation and ``enqueue_kernel``
- prototype.
-* Improved handling of integer parameters of ``enqueue_kernel`` prototype. We
- now allow ``size_t`` instead of ``int`` for specifying block parameter sizes.
-* Allow using NULL (aka ``CLK_NULL_QUEUE``) with ``queue_t``.
+clang-format
+------------
+* Option **BreakBeforeInheritanceComma** added to break before ``:`` and ``,`` in case of
+ multiple inheritance in a class declaration. Enabled by default in the Mozilla coding style.
-**Improved the following diagnostics:**
+ +---------------------+----------------------------------------+
+ | true | false |
+ +=====================+========================================+
+ | .. code-block:: c++ | .. code-block:: c++ |
+ | | |
+ | class MyClass | class MyClass : public X, public Y { |
+ | : public X | }; |
+ | , public Y { | |
+ | }; | |
+ +---------------------+----------------------------------------+
-* Disallow address spaces other than ``global`` for kernel pointer parameters.
-* Correct the use of half type argument and pointer assignment with
- dereferencing.
-* Disallow variadic arguments in functions and blocks.
-* Allow partial initializer for array and struct.
+* Align block comment decorations.
-**Some changes to OpenCL extensions have been made:**
+ +----------------------+---------------------+
+ | Before | After |
+ +======================+=====================+
+ | .. code-block:: c++ | .. code-block:: c++ |
+ | | |
+ | /* line 1 | /* line 1 |
+ | * line 2 | * line 2 |
+ | */ | */ |
+ +----------------------+---------------------+
-* Added ``cl_khr_mipmap_image``.
-* Added ``-cl-ext`` flag to allow overwriting supported extensions otherwise
- set by the target compiled for (Example: ``-cl-ext=-all,+cl_khr_fp16``).
-* New types and functions can now be flexibly added to extensions using the
- following pragmas instead of modifying the Clang source code:
+* The :doc:`ClangFormatStyleOptions` documentation provides detailed examples for most options.
- .. code-block:: c
+* Namespace end comments are now added or updated automatically.
- #pragma OPENCL EXTENSION the_new_extension_name : begin
- // declare types and functions associated with the extension here
- #pragma OPENCL EXTENSION the_new_extension_name : end
+ +---------------------+---------------------+
+ | Before | After |
+ +=====================+=====================+
+ | .. code-block:: c++ | .. code-block:: c++ |
+ | | |
+ | namespace A { | namespace A { |
+ | int i; | int i; |
+ | int j; | int j; |
+ | } | } |
+ +---------------------+---------------------+
+* Comment reflow support added. Overly long comment lines will now be reflown with the rest of
+ the paragraph instead of just broken. Option **ReflowComments** added and enabled by default.
-**Miscellaneous changes:**
+libclang
+--------
-* Fix ``__builtin_astype`` to cast between different address space objects.
-* Allow using ``opencl_unroll_hint`` with earlier OpenCL versions than 2.0.
-* Improved handling of floating point literal to default to single precision if
- fp64 extension is not enabled.
-* Refactor ``sampler_t`` implementation to simplify initializer representation
- which is now handled as a compiler builtin function with an integer value
- passed into it.
-* Change fake address space map to use the SPIR convention.
-* Added `the OpenCL manual <UsersManual.html#opencl-features>`_ to Clang
- documentation.
+...
Static Analyzer
---------------
-With the option ``--show-description``, scan-build's list of defects will also
-show the description of the defects.
+...
+
+Core Analysis Improvements
+==========================
+
+- ...
+
+New Issues Found
+================
-The analyzer now provides better support of code that uses gtest.
+- ...
-Several new checks were added:
+Python Binding Changes
+----------------------
-- The analyzer warns when virtual calls are made from constructors or
- destructors. This check is off by default but can be enabled by passing the
- following command to scan-build: ``-enable-checker optin.cplusplus.VirtualCall``.
-- The analyzer checks for synthesized copy properties of mutable types in
- Objective C, such as ``NSMutableArray``. Calling the setter for these properties
- will store an immutable copy of the value.
-- The analyzer checks for calls to ``dispatch_once()`` that use an Objective-C
- instance variable as the predicate. Using an instance variable as a predicate
- may result in the passed-in block being executed multiple times or not at all.
- These calls should be rewritten either to use a lock or to store the predicate
- in a global or static variable.
-- The analyzer checks for unintended comparisons of ``NSNumber``, ``CFNumberRef``, and
- other Cocoa number objects to scalar values.
+The following methods have been added:
+- ...
+
+Significant Known Problems
+==========================
Additional Information
======================
diff --git a/docs/SanitizerCoverage.rst b/docs/SanitizerCoverage.rst
index 3e8102a12f67..8ff5bdf3a3d2 100644
--- a/docs/SanitizerCoverage.rst
+++ b/docs/SanitizerCoverage.rst
@@ -227,7 +227,8 @@ easily used for bitset-based corpus distillation.
Caller-callee coverage
======================
-(Experimental!)
+**Deprecated, don't use**
+
Every indirect function call is instrumented with a run-time function call that
captures caller and callee. At the shutdown time the process dumps a separate
file called ``caller-callee.PID.sancov`` which contains caller/callee pairs as
@@ -253,6 +254,8 @@ Current limitations:
Coverage counters
=================
+**Deprecated, don't use**
+
This experimental feature is inspired by
`AFL <http://lcamtuf.coredump.cx/afl/technical_details.txt>`__'s coverage
instrumentation. With additional compile-time and run-time flags you can get
@@ -296,6 +299,9 @@ These counters may also be used for in-process coverage-guided fuzzers. See
Tracing basic blocks
====================
+
+**Deprecated, don't use**
+
Experimental support for basic block (or edge) tracing.
With ``-fsanitize-coverage=trace-bb`` the compiler will insert
``__sanitizer_cov_trace_basic_block(s32 *id)`` before every function, basic block, or edge
@@ -319,6 +325,9 @@ Basic block tracing is currently supported only for single-threaded applications
Tracing PCs
===========
+
+**Deprecated, don't use**
+
*Experimental* feature similar to tracing basic blocks, but with a different API.
With ``-fsanitize-coverage=trace-pc`` the compiler will insert
``__sanitizer_cov_trace_pc()`` on every edge.
@@ -331,16 +340,13 @@ and can be used with `AFL <http://lcamtuf.coredump.cx/afl>`__.
Tracing PCs with guards
=======================
-Another *experimental* feature that tries to combine the functionality of `trace-pc`,
-`8bit-counters` and boolean coverage.
With ``-fsanitize-coverage=trace-pc-guard`` the compiler will insert the following code
on every edge:
.. code-block:: none
- if (guard_variable)
- __sanitizer_cov_trace_pc_guard(&guard_variable)
+ __sanitizer_cov_trace_pc_guard(&guard_variable)
Every edge will have its own `guard_variable` (uint32_t).
@@ -349,10 +355,11 @@ The compler will also insert a module constructor that will call
.. code-block:: c++
// The guards are [start, stop).
- // This function may be called multiple times with the same values of start/stop.
+ // This function will be called at least once per DSO and may be called
+ // more than once with the same values of start/stop.
__sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop);
-Similarly to `trace-pc,indirect-calls`, with `trace-pc-guards,indirect-calls`
+With `trace-pc-guards,indirect-calls`
``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
The functions `__sanitizer_cov_trace_pc_*` should be defined by the user.
@@ -367,10 +374,10 @@ Example:
#include <sanitizer/coverage_interface.h>
// This callback is inserted by the compiler as a module constructor
- // into every compilation unit. 'start' and 'stop' correspond to the
+ // into every DSO. 'start' and 'stop' correspond to the
// beginning and end of the section with the guards for the entire
- // binary (executable or DSO) and so it will be called multiple times
- // with the same parameters.
+ // binary (executable or DSO). The callback will be called at least
+ // once per DSO and may be called multiple times with the same parameters.
extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
uint32_t *stop) {
static uint64_t N; // Counter for the guards.
diff --git a/docs/SourceBasedCodeCoverage.rst b/docs/SourceBasedCodeCoverage.rst
index abb682355b1c..474af30ae30f 100644
--- a/docs/SourceBasedCodeCoverage.rst
+++ b/docs/SourceBasedCodeCoverage.rst
@@ -18,6 +18,7 @@ Clang ships two other code coverage implementations:
various sanitizers. It can provide up to edge-level coverage.
* gcov - A GCC-compatible coverage implementation which operates on DebugInfo.
+ This is enabled by ``-ftest-coverage`` or ``--coverage``.
From this point onwards "code coverage" will refer to the source-based kind.
@@ -256,6 +257,8 @@ without using static initializers, do this manually:
otherwise. Calling this function multiple times appends profile data to an
existing on-disk raw profile.
+In C++ files, declare these as ``extern "C"``.
+
Collecting coverage reports for the llvm project
================================================
diff --git a/docs/UndefinedBehaviorSanitizer.rst b/docs/UndefinedBehaviorSanitizer.rst
index 09ee78f5876d..9bec5506359f 100644
--- a/docs/UndefinedBehaviorSanitizer.rst
+++ b/docs/UndefinedBehaviorSanitizer.rst
@@ -50,9 +50,9 @@ instead of ``clang++`` if you're compiling/linking C code.
You can enable only a subset of :ref:`checks <ubsan-checks>` offered by UBSan,
and define the desired behavior for each kind of check:
-* print a verbose error report and continue execution (default);
-* print a verbose error report and exit the program;
-* execute a trap instruction (doesn't require UBSan run-time support).
+* ``-fsanitize=...``: print a verbose error report and continue execution (default);
+* ``-fno-sanitize-recover=...``: print a verbose error report and exit the program;
+* ``-fsanitize-trap=...``: execute a trap instruction (doesn't require UBSan run-time support).
For example if you compile/link your program as:
@@ -92,6 +92,12 @@ Available checks are:
parameter which is declared to never be null.
- ``-fsanitize=null``: Use of a null pointer or creation of a null
reference.
+ - ``-fsanitize=nullability-arg``: Passing null as a function parameter
+ which is annotated with ``_Nonnull``.
+ - ``-fsanitize=nullability-assign``: Assigning null to an lvalue which
+ is annotated with ``_Nonnull``.
+ - ``-fsanitize=nullability-return``: Returning null from a function with
+ a return type annotated with ``_Nonnull``.
- ``-fsanitize=object-size``: An attempt to potentially use bytes which
the optimizer can determine are not part of the object being accessed.
This will also detect some types of undefined behavior that may not
@@ -117,7 +123,9 @@ Available checks are:
- ``-fsanitize=unreachable``: If control flow reaches
``__builtin_unreachable``.
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer
- overflows.
+ overflows. Note that unlike signed integer overflow, unsigned integer
+ is not undefined behavior. However, while it has well-defined semantics,
+ it is often unintentional, so UBSan offers to catch it.
- ``-fsanitize=vla-bound``: A variable-length array whose bound
does not evaluate to a positive value.
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that
@@ -128,11 +136,15 @@ Available checks are:
You can also use the following check groups:
- ``-fsanitize=undefined``: All of the checks listed above other than
- ``unsigned-integer-overflow``.
+ ``unsigned-integer-overflow`` and the ``nullability-*`` checks.
- ``-fsanitize=undefined-trap``: Deprecated alias of
``-fsanitize=undefined``.
- ``-fsanitize=integer``: Checks for undefined or suspicious integer
behavior (e.g. unsigned integer overflow).
+ - ``-fsanitize=nullability``: Enables ``nullability-arg``,
+ ``nullability-assign``, and ``nullability-return``. While violating
+ nullability does not have undefined behavior, it is often unintentional,
+ so UBSan offers to catch it.
Stack traces and report symbolization
=====================================
@@ -145,6 +157,8 @@ will need to:
``UBSAN_OPTIONS=print_stacktrace=1``.
#. Make sure ``llvm-symbolizer`` binary is in ``PATH``.
+Stacktrace printing for UBSan issues is currently not supported on Darwin.
+
Issue Suppression
=================
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index 6c8355776b7b..7362456202ba 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -562,6 +562,16 @@ control the crash diagnostics.
The -fno-crash-diagnostics flag can be helpful for speeding the process
of generating a delta reduced test case.
+Clang is also capable of generating preprocessed source file(s) and associated
+run script(s) even without a crash. This is specially useful when trying to
+generate a reproducer for warnings or errors while using modules.
+
+.. option:: -gen-reproducer
+
+ Generates preprocessed source files, a reproducer script and if relevant, a
+ cache containing: built module pcm's and all headers needed to rebuilt the
+ same modules.
+
.. _rpass:
Options to Emit Optimization Reports
@@ -757,6 +767,7 @@ existed.
#if foo
#endif foo // warning: extra tokens at end of #endif directive
+ #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wextra-tokens"
#if foo
@@ -1695,6 +1706,22 @@ below. If multiple flags are present, the last one is used.
Generate complete debug info.
+Controlling Macro Debug Info Generation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Debug info for C preprocessor macros increases the size of debug information in
+the binary. Macro debug info generated by Clang can be controlled by the flags
+listed below.
+
+.. option:: -fdebug-macro
+
+ Generate debug info for preprocessor macros. This flag is discarded when
+ **-g0** is enabled.
+
+.. option:: -fno-debug-macro
+
+ Do not generate debug info for preprocessor macros (default).
+
Controlling Debugger "Tuning"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1862,7 +1889,7 @@ missing from this list, please send an e-mail to cfe-dev. This list
currently excludes C++; see :ref:`C++ Language Features <cxx>`. Also, this
list does not include bugs in mostly-implemented features; please see
the `bug
-tracker <http://llvm.org/bugs/buglist.cgi?quicksearch=product%3Aclang+component%3A-New%2BBugs%2CAST%2CBasic%2CDriver%2CHeaders%2CLLVM%2BCodeGen%2Cparser%2Cpreprocessor%2CSemantic%2BAnalyzer>`_
+tracker <https://bugs.llvm.org/buglist.cgi?quicksearch=product%3Aclang+component%3A-New%2BBugs%2CAST%2CBasic%2CDriver%2CHeaders%2CLLVM%2BCodeGen%2Cparser%2Cpreprocessor%2CSemantic%2BAnalyzer>`_
for known existing bugs (FIXME: Is there a section for bug-reporting
guidelines somewhere?).
@@ -2273,7 +2300,7 @@ An example is the subgroup operations such as `intel_sub_group_shuffle
// Define custom my_sub_group_shuffle(data, c)
// that makes use of intel_sub_group_shuffle
- r1 = …
+ r1 = ...
if (r0) r1 = computeA();
// Shuffle data from r1 into r3
// of threads id r2.
@@ -2284,7 +2311,7 @@ with non-SPMD semantics this is optimized to the following equivalent code:
.. code-block:: c
- r1 = …
+ r1 = ...
if (!r0)
// Incorrect functionality! The data in r1
// have not been computed by all threads yet.
@@ -2499,7 +2526,7 @@ official `MinGW-w64 website <http://mingw-w64.sourceforge.net>`_.
Clang expects the GCC executable "gcc.exe" compiled for
``i686-w64-mingw32`` (or ``x86_64-w64-mingw32``) to be present on PATH.
-`Some tests might fail <http://llvm.org/bugs/show_bug.cgi?id=9072>`_ on
+`Some tests might fail <https://bugs.llvm.org/show_bug.cgi?id=9072>`_ on
``x86_64-w64-mingw32``.
.. _clang-cl:
@@ -2542,7 +2569,7 @@ options are spelled with a leading ``/``, they will be mistaken for a filename:
clang-cl.exe: error: no such file or directory: '/foobar'
-Please `file a bug <http://llvm.org/bugs/enter_bug.cgi?product=clang&component=Driver>`_
+Please `file a bug <https://bugs.llvm.org/enter_bug.cgi?product=clang&component=Driver>`_
for any valid cl.exe flags that clang-cl does not understand.
Execute ``clang-cl /?`` to see a list of supported options:
diff --git a/docs/analyzer/DebugChecks.rst b/docs/analyzer/DebugChecks.rst
index ecf11ca0f133..880dcfc9609c 100644
--- a/docs/analyzer/DebugChecks.rst
+++ b/docs/analyzer/DebugChecks.rst
@@ -178,15 +178,21 @@ ExprInspection checks
This function explains the value of its argument in a human-readable manner
in the warning message. You can make as many overrides of its prototype
in the test code as necessary to explain various integral, pointer,
- or even record-type values.
+ or even record-type values. To simplify usage in C code (where overloading
+ the function declaration is not allowed), you may append an arbitrary suffix
+ to the function name, without affecting functionality.
Example usage::
void clang_analyzer_explain(int);
void clang_analyzer_explain(void *);
+ // Useful in C code
+ void clang_analyzer_explain_int(int);
+
void foo(int param, void *ptr) {
clang_analyzer_explain(param); // expected-warning{{argument 'param'}}
+ clang_analyzer_explain_int(param); // expected-warning{{argument 'param'}}
if (!ptr)
clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}}
}
diff --git a/docs/analyzer/conf.py b/docs/analyzer/conf.py
index 6b54b0646eca..c40af7a5e832 100644
--- a/docs/analyzer/conf.py
+++ b/docs/analyzer/conf.py
@@ -48,10 +48,10 @@ copyright = u'2013-%d, Analyzer Team' % date.today().year
# |version| and |release|, also used in various other places throughout the
# built documents.
#
-# The short X.Y version.
-version = '4.0'
+# The short version.
+version = '5'
# The full version, including alpha/beta/rc tags.
-release = '4.0'
+release = '5'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/conf.py b/docs/conf.py
index 9cf8d3772952..a9861cd5170a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -48,10 +48,10 @@ copyright = u'2007-%d, The Clang Team' % date.today().year
# |version| and |release|, also used in various other places throughout the
# built documents.
#
-# The short X.Y version.
-version = '4'
+# The short version.
+version = '5'
# The full version, including alpha/beta/rc tags.
-release = '4'
+release = '5'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/doxygen.cfg.in b/docs/doxygen.cfg.in
index c96ab49ba0f9..ef96605ed1c1 100644
--- a/docs/doxygen.cfg.in
+++ b/docs/doxygen.cfg.in
@@ -1885,7 +1885,7 @@ ENABLE_PREPROCESSING = YES
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
@@ -1893,7 +1893,7 @@ MACRO_EXPANSION = NO
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-EXPAND_ONLY_PREDEF = NO
+EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES the includes files in the
# INCLUDE_PATH will be searched if a #include is found.
@@ -1925,7 +1925,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-PREDEFINED =
+PREDEFINED = LLVM_ALIGNAS(x)=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
diff --git a/docs/index.rst b/docs/index.rst
index 61f9c2c49426..0097ebbf65f2 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -19,6 +19,7 @@ Using Clang as a Compiler
UsersManual
Toolchain
LanguageExtensions
+ ClangCommandLineReference
AttributeReference
DiagnosticsReference
CrossCompilation
diff --git a/docs/tools/dump_format_style.py b/docs/tools/dump_format_style.py
index 6e1493949815..81a5af6ef42b 100644
--- a/docs/tools/dump_format_style.py
+++ b/docs/tools/dump_format_style.py
@@ -19,7 +19,6 @@ def substitute(text, tag, contents):
return re.sub(pattern, '%s', text, flags=re.S) % replacement
def doxygen2rst(text):
- text = re.sub(r'([^/\*])\*', r'\1\\*', text)
text = re.sub(r'<tt>\s*(.*?)\s*<\/tt>', r'``\1``', text)
text = re.sub(r'\\c ([^ ,;\.]+)', r'``\1``', text)
text = re.sub(r'\\\w+ ', '', text)
@@ -65,7 +64,7 @@ class NestedField:
self.comment = comment.strip()
def __str__(self):
- return '* ``%s`` %s' % (self.name, doxygen2rst(self.comment))
+ return '\n* ``%s`` %s' % (self.name, doxygen2rst(self.comment))
class Enum:
def __init__(self, name, comment):
diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt
index 4c6db12a4e43..e7e59d930877 100644
--- a/examples/clang-interpreter/CMakeLists.txt
+++ b/examples/clang-interpreter/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
ExecutionEngine
MC
MCJIT
+ Option
Support
native
)
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 15fde19eb974..1ac2b7f802c2 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -478,8 +478,8 @@ CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location,
unsigned *offset);
/**
- * \brief Retrieve the file, line, column, and offset represented by
- * the given source location, as specified in a # line directive.
+ * \brief Retrieve the file, line and column represented by the given source
+ * location, as specified in a # line directive.
*
* Example: given the following source code in a file somefile.c
*
@@ -3011,8 +3011,9 @@ enum CXTypeKind {
CXType_ObjCClass = 28,
CXType_ObjCSel = 29,
CXType_Float128 = 30,
+ CXType_Half = 31,
CXType_FirstBuiltin = CXType_Void,
- CXType_LastBuiltin = CXType_ObjCSel,
+ CXType_LastBuiltin = CXType_Half,
CXType_Complex = 100,
CXType_Pointer = 101,
@@ -3436,6 +3437,16 @@ CINDEX_LINKAGE long long clang_getArraySize(CXType T);
CINDEX_LINKAGE CXType clang_Type_getNamedType(CXType T);
/**
+ * \brief Determine if a typedef is 'transparent' tag.
+ *
+ * A typedef is considered 'transparent' if it shares a name and spelling
+ * location with its underlying tag type, as is the case with the NS_ENUM macro.
+ *
+ * \returns non-zero if transparent and zero otherwise.
+ */
+CINDEX_LINKAGE unsigned clang_Type_isTransparentTagTypedef(CXType T);
+
+/**
* \brief List the possible error codes for \c clang_Type_getSizeOf,
* \c clang_Type_getAlignOf, \c clang_Type_getOffsetOf and
* \c clang_Cursor_getOffsetOf.
@@ -4023,8 +4034,8 @@ CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C);
/**
* \brief Given a cursor that represents an Objective-C method or property
- * declaration, return non-zero if the declaration was affected by "@optional".
- * Returns zero if the cursor is not such a declaration or it is "@required".
+ * declaration, return non-zero if the declaration was affected by "\@optional".
+ * Returns zero if the cursor is not such a declaration or it is "\@required".
*/
CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
@@ -4700,7 +4711,7 @@ enum CXCompletionChunkKind {
*/
CXCompletionChunk_HorizontalSpace,
/**
- * Vertical space ('\n'), after which it is generally a good idea to
+ * Vertical space ('\\n'), after which it is generally a good idea to
* perform indentation.
*/
CXCompletionChunk_VerticalSpace
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1c9ce821438d..474cf2c0e3f3 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -39,6 +39,7 @@
#include "clang/Basic/SanitizerBlacklist.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/XRayLists.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -66,6 +67,7 @@
#include <memory>
#include <new>
#include <string>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -167,18 +169,20 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<DependentUnaryTransformType>
DependentUnaryTransformTypes;
mutable llvm::FoldingSet<AutoType> AutoTypes;
+ mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
+ DeducedTemplateSpecializationTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
mutable llvm::FoldingSet<PipeType> PipeTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
- mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
+ mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
SubstTemplateTemplateParms;
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
- ASTContext&>
+ ASTContext&>
SubstTemplateTemplateParmPacks;
-
+
/// \brief The set of nested name specifiers.
///
/// This set is managed by the NestedNameSpecifier class.
@@ -200,17 +204,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief A cache mapping from CXXRecordDecls to key functions.
llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions;
-
+
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
-
+
/// \brief Mapping from ObjCMethod to its duplicate declaration in the same
/// interface.
llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls;
/// \brief Mapping from __block VarDecls to their copy initialization expr.
llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
-
+
/// \brief Mapping from class scope functions specialization to their
/// template patterns.
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
@@ -226,21 +230,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// is used in canonical template names.
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
TemplateTemplateParmDecl *Parm;
-
+
public:
- CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm)
+ CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm)
: Parm(Parm) { }
-
+
TemplateTemplateParmDecl *getParam() const { return Parm; }
-
+
void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Parm); }
-
- static void Profile(llvm::FoldingSetNodeID &ID,
+
+ static void Profile(llvm::FoldingSetNodeID &ID,
TemplateTemplateParmDecl *Parm);
};
mutable llvm::FoldingSet<CanonicalTemplateTemplateParm>
CanonTemplateTemplateParms;
-
+
TemplateTemplateParmDecl *
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
@@ -259,7 +263,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief The typedef for the predefined \c id type.
mutable TypedefDecl *ObjCIdDecl;
-
+
/// \brief The typedef for the predefined \c SEL type.
mutable TypedefDecl *ObjCSelDecl;
@@ -268,7 +272,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief The typedef for the predefined \c Protocol class in Objective-C.
mutable ObjCInterfaceDecl *ObjCProtocolClassDecl;
-
+
/// \brief The typedef for the predefined 'BOOL' type.
mutable TypedefDecl *BOOLDecl;
@@ -298,12 +302,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable TypedefDecl *CFConstantStringTypeDecl;
mutable QualType ObjCSuperType;
-
+
QualType ObjCNSStringType;
/// \brief The typedef declaration for the Objective-C "instancetype" type.
TypedefDecl *ObjCInstanceTypeDecl;
-
+
/// \brief The type for the C FILE type.
TypeDecl *FILEDecl;
@@ -451,11 +455,11 @@ private:
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable;
- ParameterIndexTable ParamIndices;
-
+ ParameterIndexTable ParamIndices;
+
ImportDecl *FirstLocalImport;
ImportDecl *LastLocalImport;
-
+
TranslationUnitDecl *TUDecl;
mutable ExternCContextDecl *ExternCContext;
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl;
@@ -472,6 +476,10 @@ private:
/// entities should not be instrumented.
std::unique_ptr<SanitizerBlacklist> SanitizerBL;
+ /// \brief Function filtering mechanism to determine whether a given function
+ /// should be imbued with the XRay "always" or "never" attributes.
+ std::unique_ptr<XRayFunctionFilter> XRayFilter;
+
/// \brief The allocator used to create AST objects.
///
/// AST objects are never destructed; rather, all memory associated with the
@@ -488,7 +496,7 @@ private:
/// \brief The logical -> physical address space map.
const LangAS::Map *AddrSpaceMap;
- /// \brief Address space map mangling must be used with language specific
+ /// \brief Address space map mangling must be used with language specific
/// address spaces (e.g. OpenCL/CUDA)
bool AddrSpaceMapMangling;
@@ -500,7 +508,7 @@ private:
const TargetInfo *Target;
const TargetInfo *AuxTarget;
clang::PrintingPolicy PrintingPolicy;
-
+
public:
IdentifierTable &Idents;
SelectorTable &Selectors;
@@ -604,7 +612,7 @@ public:
void setPrintingPolicy(const clang::PrintingPolicy &Policy) {
PrintingPolicy = Policy;
}
-
+
SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; }
@@ -619,7 +627,7 @@ public:
return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
}
void Deallocate(void *Ptr) const { }
-
+
/// Return the total amount of physical memory allocated for representing
/// AST nodes and type information.
size_t getASTAllocatedMemory() const {
@@ -627,7 +635,7 @@ public:
}
/// Return the total memory used for various side tables.
size_t getSideTableAllocatedMemory() const;
-
+
PartialDiagnostic::StorageAllocator &getDiagAllocator() {
return DiagAllocator;
}
@@ -647,13 +655,17 @@ public:
QualType getRealTypeForBitwidth(unsigned DestWidth) const;
bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const;
-
+
const LangOptions& getLangOpts() const { return LangOpts; }
const SanitizerBlacklist &getSanitizerBlacklist() const {
return *SanitizerBL;
}
+ const XRayFunctionFilter &getXRayFilter() const {
+ return *XRayFilter;
+ }
+
DiagnosticsEngine &getDiagnostics() const;
FullSourceLoc getFullLoc(SourceLocation Loc) const {
@@ -862,7 +874,7 @@ public:
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
-
+
// Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
overridden_cxx_method_iterator
@@ -878,7 +890,7 @@ public:
/// \brief Note that the given C++ \p Method overrides the given \p
/// Overridden method.
- void addOverriddenMethod(const CXXMethodDecl *Method,
+ void addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden);
/// \brief Return C++ or ObjC overridden methods for the given \p Method.
@@ -891,7 +903,7 @@ public:
void getOverriddenMethods(
const NamedDecl *Method,
SmallVectorImpl<const NamedDecl *> &Overridden) const;
-
+
/// \brief Notify the AST context that a new import declaration has been
/// parsed or implicitly created within this translation unit.
void addedLocalImportDecl(ImportDecl *Import);
@@ -899,7 +911,7 @@ public:
static ImportDecl *getNextLocalImport(ImportDecl *Import) {
return Import->NextLocalImport;
}
-
+
typedef llvm::iterator_range<import_iterator> import_range;
import_range local_imports() const {
return import_range(import_iterator(FirstLocalImport), import_iterator());
@@ -973,7 +985,7 @@ public:
CanQualType SingletonId;
#include "clang/Basic/OpenCLImageTypes.def"
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
- CanQualType OCLQueueTy, OCLNDRangeTy, OCLReserveIDTy;
+ CanQualType OCLQueueTy, OCLReserveIDTy;
CanQualType OMPArraySectionTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
@@ -1179,15 +1191,15 @@ public:
/// Returns true iff we need copy/dispose helpers for the given type.
bool BlockRequiresCopying(QualType Ty, const VarDecl *D);
-
-
+
+
/// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set
/// to false in this case. If HasByrefExtendedLayout returns true, byref variable
- /// has extended lifetime.
+ /// has extended lifetime.
bool getByrefLifetime(QualType Ty,
Qualifiers::ObjCLifetime &Lifetime,
bool &HasByrefExtendedLayout) const;
-
+
/// \brief Return the uniqued reference to the type for an lvalue reference
/// to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true)
@@ -1231,7 +1243,7 @@ public:
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const;
-
+
/// \brief Returns a vla type where known sizes are replaced with [*].
QualType getVariableArrayDecayedType(QualType Ty) const;
@@ -1355,6 +1367,8 @@ public:
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args) const;
+ TemplateArgument getInjectedTemplateArg(NamedDecl *ParamDecl);
+
/// Get a template argument list with one argument per template parameter
/// in a template parameter list, such as for the injected class name of
/// a class template.
@@ -1380,7 +1394,7 @@ public:
QualType getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
ArrayRef<ObjCProtocolDecl *> protocols,
QualType Canonical = QualType()) const;
-
+
bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
/// QT's qualified-id protocol list adopt all protocols in IDecl's list
@@ -1412,6 +1426,11 @@ public:
/// \brief C++11 deduction pattern for 'auto &&' type.
QualType getAutoRRefDeductType() const;
+ /// \brief C++1z deduced class template specialization type.
+ QualType getDeducedTemplateSpecializationType(TemplateName Template,
+ QualType DeducedType,
+ bool IsDependent) const;
+
/// \brief Return the unique reference to the type for the specified TagDecl
/// (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const;
@@ -1471,11 +1490,11 @@ public:
/// \brief Return the C structure type used to represent constant CFStrings.
QualType getCFConstantStringType() const;
-
+
/// \brief Returns the C struct type for objc_super
QualType getObjCSuperType() const;
void setObjCSuperType(QualType ST) { ObjCSuperType = ST; }
-
+
/// Get the structure type used to representation CFStrings, or NULL
/// if it hasn't yet been built.
QualType getRawCFConstantStringType() const {
@@ -1496,11 +1515,11 @@ public:
QualType getObjCNSStringType() const {
return ObjCNSStringType;
}
-
+
void setObjCNSStringType(QualType T) {
ObjCNSStringType = T;
}
-
+
/// \brief Retrieve the type that \c id has been defined to, which may be
/// different from the built-in \c id if \c id has been typedef'd.
QualType getObjCIdRedefinitionType() const {
@@ -1508,7 +1527,7 @@ public:
return getObjCIdType();
return ObjCIdRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines \c id.
void setObjCIdRedefinitionType(QualType RedefType) {
ObjCIdRedefinitionType = RedefType;
@@ -1521,7 +1540,7 @@ public:
return getObjCClassType();
return ObjCClassRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines 'SEL'.
void setObjCClassRedefinitionType(QualType RedefType) {
ObjCClassRedefinitionType = RedefType;
@@ -1534,7 +1553,7 @@ public:
return getObjCSelType();
return ObjCSelRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines 'SEL'.
void setObjCSelRedefinitionType(QualType RedefType) {
ObjCSelRedefinitionType = RedefType;
@@ -1586,7 +1605,7 @@ public:
/// \brief Retrieve the typedef declaration corresponding to the Objective-C
/// "instancetype" type.
TypedefDecl *getObjCInstanceTypeDecl();
-
+
/// \brief Set the type for the C FILE type.
void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
@@ -1671,7 +1690,7 @@ public:
/// \brief Return the encoded type for this block declaration.
std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const;
-
+
/// getObjCEncodingForPropertyDecl - Return the encoded type for
/// this method declaration. If non-NULL, Container must be either
/// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should
@@ -1681,7 +1700,7 @@ public:
bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
ObjCProtocolDecl *rProto) const;
-
+
ObjCPropertyImplDecl *getObjCPropertyImplDeclForPropertyDecl(
const ObjCPropertyDecl *PD,
const Decl *Container) const;
@@ -1693,7 +1712,7 @@ public:
/// \brief Retrieve the typedef corresponding to the predefined \c id type
/// in Objective-C.
TypedefDecl *getObjCIdDecl() const;
-
+
/// \brief Represents the Objective-CC \c id type.
///
/// This is set up lazily, by Sema. \c id is always a (typedef for a)
@@ -1705,26 +1724,26 @@ public:
/// \brief Retrieve the typedef corresponding to the predefined 'SEL' type
/// in Objective-C.
TypedefDecl *getObjCSelDecl() const;
-
+
/// \brief Retrieve the type that corresponds to the predefined Objective-C
/// 'SEL' type.
- QualType getObjCSelType() const {
+ QualType getObjCSelType() const {
return getTypeDeclType(getObjCSelDecl());
}
/// \brief Retrieve the typedef declaration corresponding to the predefined
/// Objective-C 'Class' type.
TypedefDecl *getObjCClassDecl() const;
-
+
/// \brief Represents the Objective-C \c Class type.
///
/// This is set up lazily, by Sema. \c Class is always a (typedef for a)
/// pointer type, a pointer to a struct.
- QualType getObjCClassType() const {
+ QualType getObjCClassType() const {
return getTypeDeclType(getObjCClassDecl());
}
- /// \brief Retrieve the Objective-C class declaration corresponding to
+ /// \brief Retrieve the Objective-C class declaration corresponding to
/// the predefined \c Protocol class.
ObjCInterfaceDecl *getObjCProtocolDecl() const;
@@ -1742,12 +1761,12 @@ public:
QualType getBOOLType() const {
return getTypeDeclType(getBOOLDecl());
}
-
+
/// \brief Retrieve the type of the Objective-C \c Protocol class.
QualType getObjCProtoType() const {
return getObjCInterfaceType(getObjCProtocolDecl());
}
-
+
/// \brief Retrieve the C type declaration corresponding to the predefined
/// \c __builtin_va_list type.
TypedefDecl *getBuiltinVaListDecl() const;
@@ -1810,7 +1829,7 @@ public:
qs.addObjCLifetime(lifetime);
return getQualifiedType(type, qs);
}
-
+
/// getUnqualifiedObjCPointerType - Returns version of
/// Objective-C pointer type with lifetime qualifier removed.
QualType getUnqualifiedObjCPointerType(QualType type) const {
@@ -1821,7 +1840,7 @@ public:
Qs.removeObjCLifetime();
return getQualifiedType(type.getUnqualifiedType(), Qs);
}
-
+
DeclarationNameInfo getNameForTemplate(TemplateName Name,
SourceLocation NameLoc) const;
@@ -1840,7 +1859,7 @@ public:
TemplateName replacement) const;
TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
const TemplateArgument &ArgPack) const;
-
+
enum GetBuiltinTypeError {
GE_None, ///< No error
GE_Missing_stdio, ///< Missing a type from <stdio.h>
@@ -1905,7 +1924,7 @@ public:
uint64_t getCharWidth() const {
return getTypeSize(CharTy);
}
-
+
/// \brief Convert a size in bits to a size in characters.
CharUnits toCharUnitsFromBits(int64_t BitSize) const;
@@ -1927,11 +1946,11 @@ public:
/// example, from alignment attributes).
unsigned getTypeAlignIfKnown(QualType T) const;
- /// \brief Return the ABI-specified alignment of a (complete) type \p T, in
+ /// \brief Return the ABI-specified alignment of a (complete) type \p T, in
/// characters.
CharUnits getTypeAlignInChars(QualType T) const;
CharUnits getTypeAlignInChars(const Type *T) const;
-
+
// getTypeInfoDataSizeInChars - Return the size of a type, in chars. If the
// type is a record, its data size is returned.
std::pair<CharUnits, CharUnits> getTypeInfoDataSizeInChars(QualType T) const;
@@ -2036,10 +2055,10 @@ public:
VTableContextBase *getVTableContext();
MangleContext *createMangleContext();
-
+
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const;
-
+
unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const;
void CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
@@ -2115,7 +2134,7 @@ public:
*SubTnullability == NullabilityKind::Unspecified ||
*SuperTnullability == NullabilityKind::Unspecified)
return true;
-
+
if (IsParam) {
// Ok for the superclass method parameter to be "nonnull" and the subclass
// method parameter to be "nullable"
@@ -2134,9 +2153,9 @@ public:
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
const ObjCMethodDecl *MethodImp);
-
+
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
-
+
/// \brief Retrieves the "canonical" nested name specifier for a
/// given nested name specifier.
///
@@ -2190,7 +2209,7 @@ public:
/// \brief Determine whether the given template names refer to the same
/// template.
bool hasSameTemplateName(TemplateName X, TemplateName Y);
-
+
/// \brief Retrieve the "canonical" template argument.
///
/// The canonical template argument is the simplest template argument
@@ -2217,7 +2236,7 @@ public:
const {
return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T));
}
-
+
/// \brief Return the innermost element type of an array type.
///
/// For example, will return "int" for int[m][n]
@@ -2236,14 +2255,14 @@ public:
/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
QualType getAdjustedParameterType(QualType T) const;
-
+
/// \brief Retrieve the parameter type as adjusted for use in the signature
/// of a function, decaying array and function types and removing top-level
/// cv-qualifiers.
QualType getSignatureParameterType(QualType T) const;
-
+
QualType getExceptionObjectType(QualType T) const;
-
+
/// \brief Return the properly qualified result of decaying the specified
/// array type to a pointer.
///
@@ -2269,7 +2288,7 @@ public:
/// promotion occurs.
QualType isPromotableBitField(Expr *E) const;
- /// \brief Return the highest ranked integer type, see C99 6.3.1.8p1.
+ /// \brief Return the highest ranked integer type, see C99 6.3.1.8p1.
///
/// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If
/// \p LHS < \p RHS, return -1.
@@ -2298,12 +2317,7 @@ public:
return getTargetAddressSpace(Q.getAddressSpace());
}
- unsigned getTargetAddressSpace(unsigned AS) const {
- if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count)
- return AS;
- else
- return (*AddrSpaceMap)[AS - LangAS::Offset];
- }
+ unsigned getTargetAddressSpace(unsigned AS) const;
/// Get target-dependent integer value for null pointer which is used for
/// constant folding.
@@ -2311,8 +2325,7 @@ public:
bool addressSpaceMapManglingFor(unsigned AS) const {
return AddrSpaceMapMangling ||
- AS < LangAS::Offset ||
- AS >= LangAS::Offset + LangAS::Count;
+ AS >= LangAS::Count;
}
private:
@@ -2325,11 +2338,11 @@ public:
//===--------------------------------------------------------------------===//
/// Compatibility predicates used to check assignment expressions.
- bool typesAreCompatible(QualType T1, QualType T2,
+ bool typesAreCompatible(QualType T1, QualType T2,
bool CompareUnqualified = false); // C99 6.2.7p1
- bool propertyTypesAreCompatible(QualType, QualType);
- bool typesAreBlockPointerCompatible(QualType, QualType);
+ bool propertyTypesAreCompatible(QualType, QualType);
+ bool typesAreBlockPointerCompatible(QualType, QualType);
bool isObjCIdType(QualType T) const {
return T == getObjCIdType();
@@ -2344,7 +2357,7 @@ public:
bool ForCompare);
bool ObjCQualifiedClassTypesAreCompatible(QualType LHS, QualType RHS);
-
+
// Check the safety of assignment from LHS to RHS
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
@@ -2370,9 +2383,9 @@ public:
QualType mergeTransparentUnionType(QualType, QualType,
bool OfBlockPointer=false,
bool Unqualified = false);
-
+
QualType mergeObjCGCQualifiers(QualType, QualType);
-
+
bool doFunctionTypesMatchOnExtParameterInfos(
const FunctionProtoType *FromFunctionType,
const FunctionProtoType *ToFunctionType);
@@ -2442,7 +2455,7 @@ public:
/// an Objective-C method/property/ivar etc. that is part of an interface,
/// otherwise returns null.
const ObjCInterfaceDecl *getObjContainingInterface(const NamedDecl *ND) const;
-
+
/// \brief Set the copy inialization expression of a block var decl.
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
/// \brief Get the copy initialization expression of the VarDecl \p VD, or
@@ -2466,10 +2479,10 @@ public:
/// initialized to a given location, which defaults to the empty
/// location.
TypeSourceInfo *
- getTrivialTypeSourceInfo(QualType T,
+ getTrivialTypeSourceInfo(QualType T,
SourceLocation Loc = SourceLocation()) const;
- /// \brief Add a deallocation callback that will be invoked when the
+ /// \brief Add a deallocation callback that will be invoked when the
/// ASTContext is destroyed.
///
/// \param Callback A callback function that will be invoked on destruction.
@@ -2478,6 +2491,16 @@ public:
/// when it is called.
void AddDeallocation(void (*Callback)(void*), void *Data);
+ /// If T isn't trivially destructible, calls AddDeallocation to register it
+ /// for destruction.
+ template <typename T>
+ void addDestruction(T *Ptr) {
+ if (!std::is_trivially_destructible<T>::value) {
+ auto DestroyPtr = [](void *V) { static_cast<T *>(V)->~T(); };
+ AddDeallocation(DestroyPtr, Ptr);
+ }
+ }
+
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const;
GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
@@ -2534,15 +2557,15 @@ public:
/// \brief The number of implicitly-declared default constructors.
static unsigned NumImplicitDefaultConstructors;
-
- /// \brief The number of implicitly-declared default constructors for
+
+ /// \brief The number of implicitly-declared default constructors for
/// which declarations were built.
static unsigned NumImplicitDefaultConstructorsDeclared;
/// \brief The number of implicitly-declared copy constructors.
static unsigned NumImplicitCopyConstructors;
-
- /// \brief The number of implicitly-declared copy constructors for
+
+ /// \brief The number of implicitly-declared copy constructors for
/// which declarations were built.
static unsigned NumImplicitCopyConstructorsDeclared;
@@ -2555,25 +2578,25 @@ public:
/// \brief The number of implicitly-declared copy assignment operators.
static unsigned NumImplicitCopyAssignmentOperators;
-
- /// \brief The number of implicitly-declared copy assignment operators for
+
+ /// \brief The number of implicitly-declared copy assignment operators for
/// which declarations were built.
static unsigned NumImplicitCopyAssignmentOperatorsDeclared;
/// \brief The number of implicitly-declared move assignment operators.
static unsigned NumImplicitMoveAssignmentOperators;
-
- /// \brief The number of implicitly-declared move assignment operators for
+
+ /// \brief The number of implicitly-declared move assignment operators for
/// which declarations were built.
static unsigned NumImplicitMoveAssignmentOperatorsDeclared;
/// \brief The number of implicitly-declared destructors.
static unsigned NumImplicitDestructors;
-
- /// \brief The number of implicitly-declared destructors for which
+
+ /// \brief The number of implicitly-declared destructors for which
/// declarations were built.
static unsigned NumImplicitDestructorsDeclared;
-
+
public:
/// \brief Initialize built-in types.
///
diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h
index 9ae5fd62c65a..717a9e9dff34 100644
--- a/include/clang/AST/ASTVector.h
+++ b/include/clang/AST/ASTVector.h
@@ -22,6 +22,7 @@
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/type_traits.h"
#include <algorithm>
+#include <cstddef>
#include <cstring>
#include <memory>
diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
index c0c6819280d2..181131aba07f 100644
--- a/include/clang/AST/BuiltinTypes.def
+++ b/include/clang/AST/BuiltinTypes.def
@@ -169,9 +169,6 @@ BUILTIN_TYPE(OCLClkEvent, OCLClkEventTy)
// OpenCL queue_t.
BUILTIN_TYPE(OCLQueue, OCLQueueTy)
-// OpenCL ndrange_t.
-BUILTIN_TYPE(OCLNDRange, OCLNDRangeTy)
-
// OpenCL reserve_id_t.
BUILTIN_TYPE(OCLReserveID, OCLReserveIDTy)
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 8b52891af2f8..ad723a3e2b8f 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -838,7 +838,7 @@ protected:
/// Describes the kind of default argument for this parameter. By default
/// this is none. If this is normal, then the default argument is stored in
- /// the \c VarDecl initalizer expression unless we were unble to parse
+ /// the \c VarDecl initializer expression unless we were unable to parse
/// (even an invalid) expression for the default argument.
unsigned DefaultArgKind : 2;
@@ -1605,9 +1605,14 @@ private:
// FIXME: This can be packed into the bitfields in DeclContext.
// NOTE: VC++ packs bitfields poorly if the types differ.
- unsigned SClass : 2;
+ unsigned SClass : 3;
unsigned IsInline : 1;
unsigned IsInlineSpecified : 1;
+protected:
+ // This is shared by CXXConstructorDecl, CXXConversionDecl, and
+ // CXXDeductionGuideDecl.
+ unsigned IsExplicitSpecified : 1;
+private:
unsigned IsVirtualAsWritten : 1;
unsigned IsPure : 1;
unsigned HasInheritedPrototype : 1;
@@ -1708,8 +1713,9 @@ protected:
StartLoc),
DeclContext(DK), redeclarable_base(C), ParamInfo(nullptr), Body(),
SClass(S), IsInline(isInlineSpecified),
- IsInlineSpecified(isInlineSpecified), IsVirtualAsWritten(false),
- IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true),
+ IsInlineSpecified(isInlineSpecified), IsExplicitSpecified(false),
+ IsVirtualAsWritten(false), IsPure(false),
+ HasInheritedPrototype(false), HasWrittenPrototype(true),
IsDeleted(false), IsTrivial(false), IsDefaulted(false),
IsExplicitlyDefaulted(false), HasImplicitReturnZero(false),
IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
@@ -2635,12 +2641,17 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo;
llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo;
+ // FIXME: This can be packed into the bitfields in Decl.
+ /// If 0, we have not computed IsTransparentTag.
+ /// Otherwise, IsTransparentTag is (CacheIsTransparentTag >> 1).
+ mutable unsigned CacheIsTransparentTag : 2;
+
protected:
TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo)
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C),
- MaybeModedTInfo(TInfo) {}
+ MaybeModedTInfo(TInfo), CacheIsTransparentTag(0) {}
typedef Redeclarable<TypedefNameDecl> redeclarable_base;
TypedefNameDecl *getNextRedeclarationImpl() override {
@@ -2693,11 +2704,22 @@ public:
/// this typedef declaration.
TagDecl *getAnonDeclWithTypedefName(bool AnyRedecl = false) const;
+ /// Determines if this typedef shares a name and spelling location with its
+ /// underlying tag type, as is the case with the NS_ENUM macro.
+ bool isTransparentTag() const {
+ if (CacheIsTransparentTag)
+ return CacheIsTransparentTag & 0x2;
+ return isTransparentTagSlow();
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstTypedefName && K <= lastTypedefName;
}
+
+private:
+ bool isTransparentTagSlow() const;
};
/// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef'
@@ -3229,6 +3251,18 @@ public:
return isCompleteDefinition() || isFixed();
}
+ /// Returns true if this enum is either annotated with
+ /// enum_extensibility(closed) or isn't annotated with enum_extensibility.
+ bool isClosed() const;
+
+ /// Returns true if this enum is annotated with flag_enum and isn't annotated
+ /// with enum_extensibility(open).
+ bool isClosedFlag() const;
+
+ /// Returns true if this enum is annotated with neither flag_enum nor
+ /// enum_extensibility(open).
+ bool isClosedNonFlag() const;
+
/// \brief Retrieve the enum definition from which this enumeration could
/// be instantiated, if it is an instantiation (rather than a non-template).
EnumDecl *getTemplateInstantiationPattern() const;
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 5de1d0588e80..c88cb6a8fd1e 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -654,20 +654,19 @@ public:
/// a precompiled header or module) rather than having been parsed.
bool isFromASTFile() const { return FromASTFile; }
- /// \brief Retrieve the global declaration ID associated with this
- /// declaration, which specifies where in the
- unsigned getGlobalID() const {
+ /// \brief Retrieve the global declaration ID associated with this
+ /// declaration, which specifies where this Decl was loaded from.
+ unsigned getGlobalID() const {
if (isFromASTFile())
return *((const unsigned*)this - 1);
return 0;
}
-
+
/// \brief Retrieve the global ID of the module that owns this particular
/// declaration.
unsigned getOwningModuleID() const {
if (isFromASTFile())
return *((const unsigned*)this - 2);
-
return 0;
}
@@ -1030,7 +1029,7 @@ public:
void dump() const;
// Same as dump(), but forces color printing.
void dumpColor() const;
- void dump(raw_ostream &Out) const;
+ void dump(raw_ostream &Out, bool Deserialize = false) const;
/// \brief Looks through the Decl's underlying type to extract a FunctionType
/// when possible. Will return null if the type underlying the Decl does not
@@ -1811,7 +1810,8 @@ public:
void dumpDeclContext() const;
void dumpLookups() const;
- void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false) const;
+ void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false,
+ bool Deserialize = false) const;
private:
void reconcileExternalVisibleStorage() const;
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 0ca08db16299..13921a132cfb 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -203,6 +203,11 @@ public:
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
+ /// \brief Get the location at which the base class type was written.
+ SourceLocation getBaseTypeLoc() const LLVM_READONLY {
+ return BaseTypeInfo->getTypeLoc().getLocStart();
+ }
+
/// \brief Determines whether the base class is a virtual base class (or not).
bool isVirtual() const { return Virtual; }
@@ -436,9 +441,10 @@ class CXXRecordDecl : public RecordDecl {
/// either by the user or implicitly.
unsigned DeclaredSpecialMembers : 6;
- /// \brief Whether an implicit copy constructor would have a const-qualified
- /// parameter.
- unsigned ImplicitCopyConstructorHasConstParam : 1;
+ /// \brief Whether an implicit copy constructor could have a const-qualified
+ /// parameter, for initializing virtual bases and for other subobjects.
+ unsigned ImplicitCopyConstructorCanHaveConstParamForVBase : 1;
+ unsigned ImplicitCopyConstructorCanHaveConstParamForNonVBase : 1;
/// \brief Whether an implicit copy assignment operator would have a
/// const-qualified parameter.
@@ -458,6 +464,11 @@ class CXXRecordDecl : public RecordDecl {
/// \brief Whether we are currently parsing base specifiers.
unsigned IsParsingBaseSpecifiers : 1;
+ unsigned HasODRHash : 1;
+
+ /// \brief A hash of parts of the class to help in ODR checking.
+ unsigned ODRHash;
+
/// \brief The number of base class specifiers in Bases.
unsigned NumBases;
@@ -703,6 +714,8 @@ public:
return data().IsParsingBaseSpecifiers;
}
+ unsigned getODRHash() const;
+
/// \brief Sets the base classes of this struct or class.
void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
@@ -871,7 +884,9 @@ public:
/// \brief Determine whether an implicit copy constructor for this type
/// would have a parameter with a const-qualified reference type.
bool implicitCopyConstructorHasConstParam() const {
- return data().ImplicitCopyConstructorHasConstParam;
+ return data().ImplicitCopyConstructorCanHaveConstParamForNonVBase &&
+ (isAbstract() ||
+ data().ImplicitCopyConstructorCanHaveConstParamForVBase);
}
/// \brief Determine whether this class has a copy constructor with
@@ -1738,6 +1753,58 @@ public:
friend class ASTWriter;
};
+/// \brief Represents a C++ deduction guide declaration.
+///
+/// \code
+/// template<typename T> struct A { A(); A(T); };
+/// A() -> A<int>;
+/// \endcode
+///
+/// In this example, there will be an explicit deduction guide from the
+/// second line, and implicit deduction guide templates synthesized from
+/// the constructors of \c A.
+class CXXDeductionGuideDecl : public FunctionDecl {
+ void anchor() override;
+private:
+ CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+ bool IsExplicit, const DeclarationNameInfo &NameInfo,
+ QualType T, TypeSourceInfo *TInfo,
+ SourceLocation EndLocation)
+ : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
+ SC_None, false, false) {
+ if (EndLocation.isValid())
+ setRangeEnd(EndLocation);
+ IsExplicitSpecified = IsExplicit;
+ }
+
+public:
+ static CXXDeductionGuideDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, bool IsExplicit,
+ const DeclarationNameInfo &NameInfo,
+ QualType T, TypeSourceInfo *TInfo,
+ SourceLocation EndLocation);
+
+ static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ /// Whether this deduction guide is explicit.
+ bool isExplicit() const { return IsExplicitSpecified; }
+
+ /// Whether this deduction guide was declared with the 'explicit' specifier.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
+ /// Get the template for which this guide performs deduction.
+ TemplateDecl *getDeducedTemplate() const {
+ return getDeclName().getCXXDeductionGuideTemplate();
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == CXXDeductionGuide; }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
/// \brief Represents a static or instance method of a struct/union/class.
///
/// In the terminology of the C++ Standard, these are the (static and
@@ -2161,13 +2228,9 @@ class CXXConstructorDecl final
/// \{
/// \brief The arguments used to initialize the base or member.
LazyCXXCtorInitializersPtr CtorInitializers;
- unsigned NumCtorInitializers : 30;
+ unsigned NumCtorInitializers : 31;
/// \}
- /// \brief Whether this constructor declaration has the \c explicit keyword
- /// specified.
- unsigned IsExplicitSpecified : 1;
-
/// \brief Whether this constructor declaration is an implicitly-declared
/// inheriting constructor.
unsigned IsInheritingConstructor : 1;
@@ -2181,11 +2244,11 @@ class CXXConstructorDecl final
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, isConstexpr, SourceLocation()),
CtorInitializers(nullptr), NumCtorInitializers(0),
- IsExplicitSpecified(isExplicitSpecified),
IsInheritingConstructor((bool)Inherited) {
setImplicit(isImplicitlyDeclared);
if (Inherited)
*getTrailingObjects<InheritedConstructor>() = Inherited;
+ IsExplicitSpecified = isExplicitSpecified;
}
public:
@@ -2198,15 +2261,6 @@ public:
bool isConstexpr,
InheritedConstructor Inherited = InheritedConstructor());
- /// \brief Determine whether this constructor declaration has the
- /// \c explicit keyword specified.
- bool isExplicitSpecified() const { return IsExplicitSpecified; }
-
- /// \brief Determine whether this constructor was marked "explicit" or not.
- bool isExplicit() const {
- return cast<CXXConstructorDecl>(getFirstDecl())->isExplicitSpecified();
- }
-
/// \brief Iterates through the member/base initializer list.
typedef CXXCtorInitializer **init_iterator;
@@ -2270,6 +2324,14 @@ public:
CtorInitializers = Initializers;
}
+ /// Whether this function is marked as explicit explicitly.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
+ /// Whether this function is explicit.
+ bool isExplicit() const {
+ return getCanonicalDecl()->isExplicitSpecified();
+ }
+
/// \brief Determine whether this constructor is a delegating constructor.
bool isDelegatingConstructor() const {
return (getNumCtorInitializers() == 1) &&
@@ -2405,7 +2467,14 @@ public:
void setOperatorDelete(FunctionDecl *OD);
const FunctionDecl *getOperatorDelete() const {
- return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete;
+ return getCanonicalDecl()->OperatorDelete;
+ }
+
+ CXXDestructorDecl *getCanonicalDecl() override {
+ return cast<CXXDestructorDecl>(FunctionDecl::getCanonicalDecl());
+ }
+ const CXXDestructorDecl *getCanonicalDecl() const {
+ return const_cast<CXXDestructorDecl*>(this)->getCanonicalDecl();
}
// Implement isa/cast/dyncast/etc.
@@ -2428,19 +2497,16 @@ public:
/// \endcode
class CXXConversionDecl : public CXXMethodDecl {
void anchor() override;
- /// Whether this conversion function declaration is marked
- /// "explicit", meaning that it can only be applied when the user
- /// explicitly wrote a cast. This is a C++11 feature.
- bool IsExplicitSpecified : 1;
CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isExplicitSpecified,
- bool isConstexpr, SourceLocation EndLocation)
- : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, isConstexpr, EndLocation),
- IsExplicitSpecified(isExplicitSpecified) { }
+ const DeclarationNameInfo &NameInfo, QualType T,
+ TypeSourceInfo *TInfo, bool isInline,
+ bool isExplicitSpecified, bool isConstexpr,
+ SourceLocation EndLocation)
+ : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
+ SC_None, isInline, isConstexpr, EndLocation) {
+ IsExplicitSpecified = isExplicitSpecified;
+ }
public:
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
@@ -2452,17 +2518,12 @@ public:
SourceLocation EndLocation);
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
- /// Whether this conversion function declaration is marked
- /// "explicit", meaning that it can only be used for direct initialization
- /// (including explitly written casts). This is a C++11 feature.
+ /// Whether this function is marked as explicit explicitly.
bool isExplicitSpecified() const { return IsExplicitSpecified; }
- /// \brief Whether this is an explicit conversion operator (C++11 and later).
- ///
- /// Explicit conversion operators are only considered for direct
- /// initialization, e.g., when the user has explicitly written a cast.
+ /// Whether this function is explicit.
bool isExplicit() const {
- return cast<CXXConversionDecl>(getFirstDecl())->isExplicitSpecified();
+ return getCanonicalDecl()->isExplicitSpecified();
}
/// \brief Returns the type that this conversion function is converting to.
@@ -2474,6 +2535,13 @@ public:
/// a lambda closure type to a block pointer.
bool isLambdaToBlockPointerConversion() const;
+ CXXConversionDecl *getCanonicalDecl() override {
+ return cast<CXXConversionDecl>(FunctionDecl::getCanonicalDecl());
+ }
+ const CXXConversionDecl *getCanonicalDecl() const {
+ return const_cast<CXXConversionDecl*>(this)->getCanonicalDecl();
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == CXXConversion; }
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index ff37758c2551..eb86526e8eca 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -131,7 +131,7 @@ public:
} else {
DeclsTy &Vec = *getAsVector();
Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
- std::mem_fun(&Decl::isFromASTFile)),
+ [](Decl *D) { return D->isFromASTFile(); }),
Vec.end());
// Don't have any external decls any more.
Data = DeclsAndHasExternalTy(&Vec, false);
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index f5098f06a9f6..26c0cbe82d17 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -381,15 +381,17 @@ public:
ArrayRef<SourceLocation> SelLocs = llvm::None);
// Iterator access to parameter types.
- typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun;
- typedef llvm::mapped_iterator<param_const_iterator, deref_fun>
- param_type_iterator;
+ struct GetTypeFn {
+ QualType operator()(const ParmVarDecl *PD) const { return PD->getType(); }
+ };
+ typedef llvm::mapped_iterator<param_const_iterator, GetTypeFn>
+ param_type_iterator;
param_type_iterator param_type_begin() const {
- return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType));
+ return llvm::map_iterator(param_begin(), GetTypeFn());
}
param_type_iterator param_type_end() const {
- return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType));
+ return llvm::map_iterator(param_end(), GetTypeFn());
}
/// createImplicitParams - Used to lazily create the self and cmd
@@ -743,6 +745,8 @@ private:
Selector GetterName; // getter name of NULL if no getter
Selector SetterName; // setter name of NULL if no setter
+ SourceLocation GetterNameLoc; // location of the getter attribute's value
+ SourceLocation SetterNameLoc; // location of the setter attribute's value
ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method
ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method
@@ -855,10 +859,18 @@ public:
}
Selector getGetterName() const { return GetterName; }
- void setGetterName(Selector Sel) { GetterName = Sel; }
+ SourceLocation getGetterNameLoc() const { return GetterNameLoc; }
+ void setGetterName(Selector Sel, SourceLocation Loc = SourceLocation()) {
+ GetterName = Sel;
+ GetterNameLoc = Loc;
+ }
Selector getSetterName() const { return SetterName; }
- void setSetterName(Selector Sel) { SetterName = Sel; }
+ SourceLocation getSetterNameLoc() const { return SetterNameLoc; }
+ void setSetterName(Selector Sel, SourceLocation Loc = SourceLocation()) {
+ SetterName = Sel;
+ SetterNameLoc = Loc;
+ }
ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; }
@@ -2320,11 +2332,9 @@ class ObjCImplDecl : public ObjCContainerDecl {
protected:
ObjCImplDecl(Kind DK, DeclContext *DC,
ObjCInterfaceDecl *classInterface,
+ IdentifierInfo *Id,
SourceLocation nameLoc, SourceLocation atStartLoc)
- : ObjCContainerDecl(DK, DC,
- classInterface? classInterface->getIdentifier()
- : nullptr,
- nameLoc, atStartLoc),
+ : ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc),
ClassInterface(classInterface) {}
public:
@@ -2386,9 +2396,6 @@ public:
class ObjCCategoryImplDecl : public ObjCImplDecl {
void anchor() override;
- // Category name
- IdentifierInfo *Id;
-
// Category name location
SourceLocation CategoryNameLoc;
@@ -2396,8 +2403,9 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc, SourceLocation atStartLoc,
SourceLocation CategoryNameLoc)
- : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, nameLoc, atStartLoc),
- Id(Id), CategoryNameLoc(CategoryNameLoc) {}
+ : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id,
+ nameLoc, atStartLoc),
+ CategoryNameLoc(CategoryNameLoc) {}
public:
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
@@ -2407,37 +2415,10 @@ public:
SourceLocation CategoryNameLoc);
static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
- /// getIdentifier - Get the identifier that names the category
- /// interface associated with this implementation.
- /// FIXME: This is a bad API, we are hiding NamedDecl::getIdentifier()
- /// with a different meaning. For example:
- /// ((NamedDecl *)SomeCategoryImplDecl)->getIdentifier()
- /// returns the class interface name, whereas
- /// ((ObjCCategoryImplDecl *)SomeCategoryImplDecl)->getIdentifier()
- /// returns the category name.
- IdentifierInfo *getIdentifier() const {
- return Id;
- }
- void setIdentifier(IdentifierInfo *II) { Id = II; }
-
ObjCCategoryDecl *getCategoryDecl() const;
SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
- /// getName - Get the name of identifier for the class interface associated
- /// with this implementation as a StringRef.
- //
- // FIXME: This is a bad API, we are hiding NamedDecl::getName with a different
- // meaning.
- StringRef getName() const { return Id ? Id->getName() : StringRef(); }
-
- /// @brief Get the name of the class associated with this interface.
- //
- // FIXME: Deprecated, move clients to getName().
- std::string getNameAsString() const {
- return getName();
- }
-
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
@@ -2493,7 +2474,10 @@ class ObjCImplementationDecl : public ObjCImplDecl {
SourceLocation superLoc = SourceLocation(),
SourceLocation IvarLBraceLoc=SourceLocation(),
SourceLocation IvarRBraceLoc=SourceLocation())
- : ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc),
+ : ObjCImplDecl(ObjCImplementation, DC, classInterface,
+ classInterface ? classInterface->getIdentifier()
+ : nullptr,
+ nameLoc, atStartLoc),
SuperClass(superDecl), SuperLoc(superLoc), IvarLBraceLoc(IvarLBraceLoc),
IvarRBraceLoc(IvarRBraceLoc),
IvarInitializers(nullptr), NumIvarInitializers(0),
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index dc50a190de42..2879452f2404 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -344,6 +344,32 @@ public:
// Kinds of Templates
//===----------------------------------------------------------------------===//
+/// \brief Stores the template parameter list and associated constraints for
+/// \c TemplateDecl objects that track associated constraints.
+class ConstrainedTemplateDeclInfo {
+ friend TemplateDecl;
+
+public:
+ ConstrainedTemplateDeclInfo() : TemplateParams(), AssociatedConstraints() {}
+
+ TemplateParameterList *getTemplateParameters() const {
+ return TemplateParams;
+ }
+
+ Expr *getAssociatedConstraints() const { return AssociatedConstraints; }
+
+protected:
+ void setTemplateParameters(TemplateParameterList *TParams) {
+ TemplateParams = TParams;
+ }
+
+ void setAssociatedConstraints(Expr *AC) { AssociatedConstraints = AC; }
+
+ TemplateParameterList *TemplateParams;
+ Expr *AssociatedConstraints;
+};
+
+
/// \brief The base class of all kinds of template declarations (e.g.,
/// class, function, etc.).
///
@@ -352,33 +378,53 @@ public:
class TemplateDecl : public NamedDecl {
void anchor() override;
protected:
- // This is probably never used.
- TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name)
+ // Construct a template decl with the given name and parameters.
+ // Used when there is no templated element (e.g., for tt-params).
+ TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
- TemplateParams(nullptr) {}
+ TemplateParams(CTDI) {
+ this->setTemplateParameters(Params);
+ }
- // Construct a template decl with the given name and parameters.
- // Used when there is not templated element (tt-params).
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params)
- : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
- TemplateParams(Params) {}
+ : TemplateDecl(nullptr, DK, DC, L, Name, Params) {}
// Construct a template decl with name, parameters, and templated element.
- TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false),
- TemplateParams(Params) {}
+ TemplateParams(CTDI) {
+ this->setTemplateParameters(Params);
+ }
+
+ TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl)
+ : TemplateDecl(nullptr, DK, DC, L, Name, Params, Decl) {}
public:
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- return TemplateParams;
+ const auto *const CTDI =
+ TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
+ return CTDI ? CTDI->getTemplateParameters()
+ : TemplateParams.get<TemplateParameterList *>();
}
/// Get the constraint-expression from the associated requires-clause (if any)
const Expr *getRequiresClause() const {
- return TemplateParams ? TemplateParams->getRequiresClause() : nullptr;
+ const TemplateParameterList *const TP = getTemplateParameters();
+ return TP ? TP->getRequiresClause() : nullptr;
+ }
+
+ Expr *getAssociatedConstraints() const {
+ const TemplateDecl *const C = cast<TemplateDecl>(getCanonicalDecl());
+ const auto *const CTDI =
+ C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
+ return CTDI ? CTDI->getAssociatedConstraints() : nullptr;
}
/// Get the underlying, templated declaration.
@@ -391,7 +437,7 @@ public:
}
SourceRange getSourceRange() const override LLVM_READONLY {
- return SourceRange(TemplateParams->getTemplateLoc(),
+ return SourceRange(getTemplateParameters()->getTemplateLoc(),
TemplatedDecl.getPointer()->getSourceRange().getEnd());
}
@@ -407,7 +453,29 @@ protected:
/// (function or variable) is a concept.
llvm::PointerIntPair<NamedDecl *, 1, bool> TemplatedDecl;
- TemplateParameterList* TemplateParams;
+ /// \brief The template parameter list and optional requires-clause
+ /// associated with this declaration; alternatively, a
+ /// \c ConstrainedTemplateDeclInfo if the associated constraints of the
+ /// template are being tracked by this particular declaration.
+ llvm::PointerUnion<TemplateParameterList *,
+ ConstrainedTemplateDeclInfo *>
+ TemplateParams;
+
+ void setTemplateParameters(TemplateParameterList *TParams) {
+ if (auto *const CTDI =
+ TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>()) {
+ CTDI->setTemplateParameters(TParams);
+ } else {
+ TemplateParams = TParams;
+ }
+ }
+
+ void setAssociatedConstraints(Expr *AC) {
+ assert(isCanonicalDecl() &&
+ "Attaching associated constraints to non-canonical Decl");
+ TemplateParams.get<ConstrainedTemplateDeclInfo *>()
+ ->setAssociatedConstraints(AC);
+ }
public:
/// \brief Initialize the underlying templated declaration and
@@ -737,11 +805,17 @@ protected:
virtual CommonBase *newCommon(ASTContext &C) const = 0;
// Construct a template decl with name, parameters, and templated element.
+ RedeclarableTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK,
+ ASTContext &C, DeclContext *DC, SourceLocation L,
+ DeclarationName Name, TemplateParameterList *Params,
+ NamedDecl *Decl)
+ : TemplateDecl(CTDI, DK, DC, L, Name, Params, Decl), redeclarable_base(C),
+ Common() {}
+
RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
- : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C),
- Common() {}
+ : RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {}
public:
template <class decl_type> friend class RedeclarableTemplate;
@@ -863,8 +937,6 @@ SpecEntryTraits<FunctionTemplateSpecializationInfo> {
/// Declaration of a template function.
class FunctionTemplateDecl : public RedeclarableTemplateDecl {
- static void DeallocateCommon(void *Ptr);
-
protected:
/// \brief Data that is common to all of the declarations of a given
/// function template.
@@ -1407,7 +1479,9 @@ public:
unsigned NumExpansions);
using TemplateParmPosition::getDepth;
+ using TemplateParmPosition::setDepth;
using TemplateParmPosition::getPosition;
+ using TemplateParmPosition::setPosition;
using TemplateParmPosition::getIndex;
/// \brief Whether this template template parameter is a template
@@ -1960,8 +2034,6 @@ public:
/// Declaration of a class template.
class ClassTemplateDecl : public RedeclarableTemplateDecl {
- static void DeallocateCommon(void *Ptr);
-
protected:
/// \brief Data that is common to all of the declarations of a given
/// class template.
@@ -1997,10 +2069,16 @@ protected:
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
getPartialSpecializations();
+ ClassTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, ASTContext &C,
+ DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl)
+ : RedeclarableTemplateDecl(CTDI, ClassTemplate, C, DC, L, Name, Params,
+ Decl) {}
+
ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
DeclarationName Name, TemplateParameterList *Params,
NamedDecl *Decl)
- : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
+ : ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {}
CommonBase *newCommon(ASTContext &C) const override;
@@ -2023,12 +2101,14 @@ public:
return getTemplatedDecl()->isThisDeclarationADefinition();
}
+ // FIXME: remove default argument for AssociatedConstraints
/// \brief Create a class template node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl);
+ NamedDecl *Decl,
+ Expr *AssociatedConstraints = nullptr);
/// \brief Create an empty class template node.
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2247,8 +2327,6 @@ public:
/// template \<typename T> using V = std::map<T*, int, MyCompare<T>>;
/// \endcode
class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
- static void DeallocateCommon(void *Ptr);
-
protected:
typedef CommonBase Common;
@@ -2773,8 +2851,6 @@ public:
/// Declaration of a variable template.
class VarTemplateDecl : public RedeclarableTemplateDecl {
- static void DeallocateCommon(void *Ptr);
-
protected:
/// \brief Data that is common to all of the declarations of a given
/// variable template.
@@ -2946,6 +3022,16 @@ inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
return P.get<TemplateTemplateParmDecl*>();
}
+inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) {
+ auto *TD = dyn_cast<TemplateDecl>(D);
+ return TD && (isa<ClassTemplateDecl>(TD) ||
+ isa<ClassTemplatePartialSpecializationDecl>(TD) ||
+ isa<TypeAliasTemplateDecl>(TD) ||
+ isa<TemplateTemplateParmDecl>(TD))
+ ? TD
+ : nullptr;
+}
+
} /* end of namespace clang */
#endif
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 2d3cfe27a165..5e773c968384 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -23,6 +23,7 @@ namespace llvm {
namespace clang {
class ASTContext;
+ class CXXDeductionGuideNameExtra;
class CXXLiteralOperatorIdName;
class CXXOperatorIdName;
class CXXSpecialName;
@@ -32,6 +33,7 @@ namespace clang {
enum OverloadedOperatorKind : int;
struct PrintingPolicy;
class QualType;
+ class TemplateDecl;
class Type;
class TypeSourceInfo;
class UsingDirectiveDecl;
@@ -56,6 +58,7 @@ public:
CXXConstructorName,
CXXDestructorName,
CXXConversionFunctionName,
+ CXXDeductionGuideName,
CXXOperatorName,
CXXLiteralOperatorName,
CXXUsingDirective
@@ -118,42 +121,36 @@ private:
CXXSpecialName *getAsCXXSpecialName() const {
NameKind Kind = getNameKind();
if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName)
- return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
+ return reinterpret_cast<CXXSpecialName *>(getExtra());
+ return nullptr;
+ }
+
+ /// If the stored pointer is actually a CXXDeductionGuideNameExtra, returns a
+ /// pointer to it. Otherwise, returns a NULL pointer.
+ CXXDeductionGuideNameExtra *getAsCXXDeductionGuideNameExtra() const {
+ if (getNameKind() == CXXDeductionGuideName)
+ return reinterpret_cast<CXXDeductionGuideNameExtra *>(getExtra());
return nullptr;
}
/// getAsCXXOperatorIdName
CXXOperatorIdName *getAsCXXOperatorIdName() const {
if (getNameKind() == CXXOperatorName)
- return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
+ return reinterpret_cast<CXXOperatorIdName *>(getExtra());
return nullptr;
}
CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const {
if (getNameKind() == CXXLiteralOperatorName)
- return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask);
+ return reinterpret_cast<CXXLiteralOperatorIdName *>(getExtra());
return nullptr;
}
// Construct a declaration name from the name of a C++ constructor,
// destructor, or conversion function.
- DeclarationName(CXXSpecialName *Name)
- : Ptr(reinterpret_cast<uintptr_t>(Name)) {
- assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
- Ptr |= StoredDeclarationNameExtra;
- }
-
- // Construct a declaration name from the name of a C++ overloaded
- // operator.
- DeclarationName(CXXOperatorIdName *Name)
+ DeclarationName(DeclarationNameExtra *Name)
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
- assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
- Ptr |= StoredDeclarationNameExtra;
- }
-
- DeclarationName(CXXLiteralOperatorIdName *Name)
- : Ptr(reinterpret_cast<uintptr_t>(Name)) {
- assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId");
+ assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra");
Ptr |= StoredDeclarationNameExtra;
}
@@ -252,6 +249,10 @@ public:
/// type associated with that name.
QualType getCXXNameType() const;
+ /// If this name is the name of a C++ deduction guide, return the
+ /// template associated with that name.
+ TemplateDecl *getCXXDeductionGuideTemplate() const;
+
/// getCXXOverloadedOperator - If this name is the name of an
/// overloadable operator in C++ (e.g., @c operator+), retrieve the
/// kind of overloaded operator.
@@ -346,6 +347,7 @@ class DeclarationNameTable {
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
CXXOperatorIdName *CXXOperatorNames; // Operator names
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
+ void *CXXDeductionGuideNames; // FoldingSet<CXXDeductionGuideNameExtra> *
DeclarationNameTable(const DeclarationNameTable&) = delete;
void operator=(const DeclarationNameTable&) = delete;
@@ -368,6 +370,9 @@ public:
/// for the given Type.
DeclarationName getCXXDestructorName(CanQualType Ty);
+ /// Returns the name of a C++ deduction guide for the given template.
+ DeclarationName getCXXDeductionGuideName(TemplateDecl *TD);
+
/// getCXXConversionFunctionName - Returns the name of a C++
/// conversion function for the given Type.
DeclarationName getCXXConversionFunctionName(CanQualType Ty);
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 56b99ccd8971..986145e62a52 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -115,6 +115,7 @@ protected:
ExprBits.InstantiationDependent = ID;
ExprBits.ValueKind = VK;
ExprBits.ObjectKind = OK;
+ assert(ExprBits.ObjectKind == OK && "truncated kind");
ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
setType(T);
}
@@ -907,6 +908,10 @@ public:
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
/// The source expression of an opaque value expression is the
/// expression which originally generated the value. This is
/// provided as a convenience for analyses that don't wish to
@@ -1167,6 +1172,10 @@ public:
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -1222,6 +1231,9 @@ public:
// Iterators
child_range children() { return child_range(&FnName, &FnName + 1); }
+ const_child_range children() const {
+ return const_child_range(&FnName, &FnName + 1);
+ }
friend class ASTStmtReader;
};
@@ -1315,6 +1327,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
class CharacterLiteral : public Expr {
@@ -1365,6 +1380,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
class FloatingLiteral : public Expr, private APFloatStorage {
@@ -1429,6 +1447,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// ImaginaryLiteral - We support imaginary integer and floating point literals,
@@ -1461,6 +1482,9 @@ public:
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
+ const_child_range children() const {
+ return const_child_range(&Val, &Val + 1);
+ }
};
/// StringLiteral - This represents a string literal expression, e.g. "foo"
@@ -1628,6 +1652,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
@@ -1669,6 +1696,9 @@ public:
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
+ const_child_range children() const {
+ return const_child_range(&Val, &Val + 1);
+ }
};
/// UnaryOperator - This represents the unary-expression's (except sizeof and
@@ -1778,6 +1808,9 @@ public:
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
+ const_child_range children() const {
+ return const_child_range(&Val, &Val + 1);
+ }
};
/// Helper class for OffsetOfExpr.
@@ -1981,6 +2014,11 @@ public:
Stmt **begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
return child_range(begin, begin + NumExprs);
}
+ const_child_range children() const {
+ Stmt *const *begin =
+ reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
+ return const_child_range(begin, begin + NumExprs);
+ }
friend TrailingObjects;
};
@@ -2069,6 +2107,7 @@ public:
// Iterators
child_range children();
+ const_child_range children() const;
};
//===----------------------------------------------------------------------===//
@@ -2153,6 +2192,9 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
};
/// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
@@ -2313,6 +2355,11 @@ public:
return child_range(&SubExprs[0],
&SubExprs[0]+NumArgs+getNumPreArgs()+PREARGS_START);
}
+
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + NumArgs +
+ getNumPreArgs() + PREARGS_START);
+ }
};
/// Extra data stored in some MemberExpr objects.
@@ -2567,6 +2614,9 @@ public:
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
+ const_child_range children() const {
+ return const_child_range(&Base, &Base + 1);
+ }
friend TrailingObjects;
friend class ASTReader;
@@ -2639,6 +2689,9 @@ public:
// Iterators
child_range children() { return child_range(&Init, &Init+1); }
+ const_child_range children() const {
+ return const_child_range(&Init, &Init + 1);
+ }
};
/// CastExpr - Base class for type casts, including both implicit
@@ -2725,6 +2778,7 @@ public:
// Iterators
child_range children() { return child_range(&Op, &Op+1); }
+ const_child_range children() const { return const_child_range(&Op, &Op + 1); }
};
/// ImplicitCastExpr - Allows us to explicitly represent implicit type
@@ -2917,11 +2971,9 @@ public:
private:
unsigned Opc : 6;
- // Records the FP_CONTRACT pragma status at the point that this binary
- // operator was parsed. This bit is only meaningful for operations on
- // floating point types. For all other types it should default to
- // false.
- unsigned FPContractable : 1;
+ // This is only meaningful for operations on floating point types and 0
+ // otherwise.
+ unsigned FPFeatures : 2;
SourceLocation OpLoc;
enum { LHS, RHS, END_EXPR };
@@ -2930,7 +2982,7 @@ public:
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
- SourceLocation opLoc, bool fpContractable)
+ SourceLocation opLoc, FPOptions FPFeatures)
: Expr(BinaryOperatorClass, ResTy, VK, OK,
lhs->isTypeDependent() || rhs->isTypeDependent(),
lhs->isValueDependent() || rhs->isValueDependent(),
@@ -2938,7 +2990,7 @@ public:
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
- Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
+ Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
assert(!isCompoundAssignmentOp() &&
@@ -3070,19 +3122,26 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
// Set the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- void setFPContractable(bool FPC) { FPContractable = FPC; }
+ void setFPFeatures(FPOptions F) { FPFeatures = F.getInt(); }
+
+ FPOptions getFPFeatures() const { return FPOptions(FPFeatures); }
// Get the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- bool isFPContractable() const { return FPContractable; }
+ bool isFPContractableWithinStatement() const {
+ return FPOptions(FPFeatures).allowFPContractWithinStatement();
+ }
protected:
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
- SourceLocation opLoc, bool fpContractable, bool dead2)
+ SourceLocation opLoc, FPOptions FPFeatures, bool dead2)
: Expr(CompoundAssignOperatorClass, ResTy, VK, OK,
lhs->isTypeDependent() || rhs->isTypeDependent(),
lhs->isValueDependent() || rhs->isValueDependent(),
@@ -3090,7 +3149,7 @@ protected:
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
- Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
+ Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
}
@@ -3112,8 +3171,8 @@ public:
CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
ExprValueKind VK, ExprObjectKind OK,
QualType CompLHSType, QualType CompResultType,
- SourceLocation OpLoc, bool fpContractable)
- : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable,
+ SourceLocation OpLoc, FPOptions FPFeatures)
+ : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures,
true),
ComputationLHSType(CompLHSType),
ComputationResultType(CompResultType) {
@@ -3246,6 +3305,9 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
};
/// BinaryConditionalOperator - The GNU extension to the conditional
@@ -3331,6 +3393,9 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs + NUM_SUBEXPRS);
}
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + NUM_SUBEXPRS);
+ }
};
inline Expr *AbstractConditionalOperator::getCond() const {
@@ -3385,6 +3450,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
@@ -3427,6 +3495,9 @@ public:
// Iterators
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
+ const_child_range children() const {
+ return const_child_range(&SubStmt, &SubStmt + 1);
+ }
};
/// ShuffleVectorExpr - clang-specific builtin-in function
@@ -3495,6 +3566,9 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+NumExprs);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + NumExprs);
+ }
};
/// ConvertVectorExpr - Clang builtin function __builtin_convertvector
@@ -3549,6 +3623,9 @@ public:
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
+ const_child_range children() const {
+ return const_child_range(&SrcExpr, &SrcExpr + 1);
+ }
};
/// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
@@ -3629,6 +3706,9 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
};
/// GNUNullExpr - Implements the GNU __null extension, which is a name
@@ -3665,6 +3745,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// Represents a call to the builtin function \c __builtin_va_arg.
@@ -3712,6 +3795,9 @@ public:
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
+ const_child_range children() const {
+ return const_child_range(&Val, &Val + 1);
+ }
};
/// @brief Describes an C or C++ initializer list.
@@ -3936,10 +4022,16 @@ public:
// Iterators
child_range children() {
+ const_child_range CCR = const_cast<const InitListExpr *>(this)->children();
+ return child_range(cast_away_const(CCR.begin()),
+ cast_away_const(CCR.end()));
+ }
+
+ const_child_range children() const {
// FIXME: This does not include the array filler expression.
if (InitExprs.empty())
- return child_range(child_iterator(), child_iterator());
- return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size());
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ return const_child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size());
}
typedef InitExprsTy::iterator iterator;
@@ -4254,6 +4346,10 @@ public:
Stmt **begin = getTrailingObjects<Stmt *>();
return child_range(begin, begin + NumSubExprs);
}
+ const_child_range children() const {
+ Stmt * const *begin = getTrailingObjects<Stmt *>();
+ return const_child_range(begin, begin + NumSubExprs);
+ }
friend TrailingObjects;
};
@@ -4287,6 +4383,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
// In cases like:
@@ -4332,6 +4431,10 @@ public:
child_range children() {
return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2);
}
+ const_child_range children() const {
+ return const_child_range(&BaseAndUpdaterExprs[0],
+ &BaseAndUpdaterExprs[0] + 2);
+ }
};
/// \brief Represents a loop initializing the elements of an array.
@@ -4393,6 +4496,9 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs + 2);
}
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + 2);
+ }
friend class ASTReader;
friend class ASTStmtReader;
@@ -4421,6 +4527,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
friend class ASTReader;
friend class ASTStmtReader;
@@ -4455,6 +4564,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
class ParenListExpr : public Expr {
@@ -4501,6 +4613,9 @@ public:
child_range children() {
return child_range(&Exprs[0], &Exprs[0]+NumExprs);
}
+ const_child_range children() const {
+ return const_child_range(&Exprs[0], &Exprs[0] + NumExprs);
+ }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -4621,7 +4736,9 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs);
}
-
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + END_EXPR + NumAssocs);
+ }
friend class ASTStmtReader;
};
@@ -4690,6 +4807,9 @@ public:
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
+ const_child_range children() const {
+ return const_child_range(&Base, &Base + 1);
+ }
};
/// BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
@@ -4731,6 +4851,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
@@ -4776,6 +4899,9 @@ public:
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
+ const_child_range children() const {
+ return const_child_range(&SrcExpr, &SrcExpr + 1);
+ }
};
/// PseudoObjectExpr - An expression which accesses a pseudo-object
@@ -4914,8 +5040,15 @@ public:
}
child_range children() {
- Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer());
- return child_range(cs, cs + getNumSubExprs());
+ const_child_range CCR =
+ const_cast<const PseudoObjectExpr *>(this)->children();
+ return child_range(cast_away_const(CCR.begin()),
+ cast_away_const(CCR.end()));
+ }
+ const_child_range children() const {
+ Stmt *const *cs = const_cast<Stmt *const *>(
+ reinterpret_cast<const Stmt *const *>(getSubExprsBuffer()));
+ return const_child_range(cs, cs + getNumSubExprs());
}
static bool classof(const Stmt *T) {
@@ -5021,6 +5154,9 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs+NumSubExprs);
}
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + NumSubExprs);
+ }
};
/// TypoExpr - Internal placeholder for expressions where typo correction
@@ -5039,6 +5175,10 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 37e59771a723..79d2c58099c4 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -54,18 +54,16 @@ class CXXOperatorCallExpr : public CallExpr {
OverloadedOperatorKind Operator;
SourceRange Range;
- // Record the FP_CONTRACT state that applies to this operator call. Only
- // meaningful for floating point types. For other types this value can be
- // set to false.
- unsigned FPContractable : 1;
+ // Only meaningful for floating point types.
+ FPOptions FPFeatures;
SourceRange getSourceRangeImpl() const LLVM_READONLY;
public:
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
- SourceLocation operatorloc, bool fpContractable)
+ SourceLocation operatorloc, FPOptions FPFeatures)
: CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc),
- Operator(Op), FPContractable(fpContractable) {
+ Operator(Op), FPFeatures(FPFeatures) {
Range = getSourceRangeImpl();
}
explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
@@ -113,11 +111,15 @@ public:
// Set the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- void setFPContractable(bool FPC) { FPContractable = FPC; }
+ void setFPFeatures(FPOptions F) { FPFeatures = F; }
+
+ FPOptions getFPFeatures() const { return FPFeatures; }
// Get the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- bool isFPContractable() const { return FPContractable; }
+ bool isFPContractableWithinStatement() const {
+ return FPFeatures.allowFPContractWithinStatement();
+ }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -1470,7 +1472,8 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
public:
CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
- TypeSourceInfo *Type,
+ QualType Type,
+ TypeSourceInfo *TSI,
ArrayRef<Expr *> Args,
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
@@ -4122,16 +4125,18 @@ class CoroutineSuspendExpr : public Expr {
enum SubExpr { Common, Ready, Suspend, Resume, Count };
Stmt *SubExprs[SubExpr::Count];
+ OpaqueValueExpr *OpaqueValue = nullptr;
friend class ASTStmtReader;
public:
CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Common,
- Expr *Ready, Expr *Suspend, Expr *Resume)
+ Expr *Ready, Expr *Suspend, Expr *Resume,
+ OpaqueValueExpr *OpaqueValue)
: Expr(SC, Resume->getType(), Resume->getValueKind(),
Resume->getObjectKind(), Resume->isTypeDependent(),
Resume->isValueDependent(), Common->isInstantiationDependent(),
Common->containsUnexpandedParameterPack()),
- KeywordLoc(KeywordLoc) {
+ KeywordLoc(KeywordLoc), OpaqueValue(OpaqueValue) {
SubExprs[SubExpr::Common] = Common;
SubExprs[SubExpr::Ready] = Ready;
SubExprs[SubExpr::Suspend] = Suspend;
@@ -4160,6 +4165,8 @@ public:
Expr *getCommonExpr() const {
return static_cast<Expr*>(SubExprs[SubExpr::Common]);
}
+ /// \brief getOpaqueValue - Return the opaque value placeholder.
+ OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; }
Expr *getReadyExpr() const {
return static_cast<Expr*>(SubExprs[SubExpr::Ready]);
@@ -4193,11 +4200,17 @@ class CoawaitExpr : public CoroutineSuspendExpr {
friend class ASTStmtReader;
public:
CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready,
- Expr *Suspend, Expr *Resume)
+ Expr *Suspend, Expr *Resume, OpaqueValueExpr *OpaqueValue,
+ bool IsImplicit = false)
: CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Operand, Ready,
- Suspend, Resume) {}
- CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand)
- : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {}
+ Suspend, Resume, OpaqueValue) {
+ CoawaitBits.IsImplicit = IsImplicit;
+ }
+ CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand,
+ bool IsImplicit = false)
+ : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {
+ CoawaitBits.IsImplicit = IsImplicit;
+ }
CoawaitExpr(EmptyShell Empty)
: CoroutineSuspendExpr(CoawaitExprClass, Empty) {}
@@ -4206,19 +4219,67 @@ public:
return getCommonExpr();
}
+ bool isImplicit() const { return CoawaitBits.IsImplicit; }
+ void setIsImplicit(bool value = true) { CoawaitBits.IsImplicit = value; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CoawaitExprClass;
}
};
+/// \brief Represents a 'co_await' expression while the type of the promise
+/// is dependent.
+class DependentCoawaitExpr : public Expr {
+ SourceLocation KeywordLoc;
+ Stmt *SubExprs[2];
+
+ friend class ASTStmtReader;
+
+public:
+ DependentCoawaitExpr(SourceLocation KeywordLoc, QualType Ty, Expr *Op,
+ UnresolvedLookupExpr *OpCoawait)
+ : Expr(DependentCoawaitExprClass, Ty, VK_RValue, OK_Ordinary,
+ /*TypeDependent*/ true, /*ValueDependent*/ true,
+ /*InstantiationDependent*/ true,
+ Op->containsUnexpandedParameterPack()),
+ KeywordLoc(KeywordLoc) {
+ // NOTE: A co_await expression is dependent on the coroutines promise
+ // type and may be dependent even when the `Op` expression is not.
+ assert(Ty->isDependentType() &&
+ "wrong constructor for non-dependent co_await/co_yield expression");
+ SubExprs[0] = Op;
+ SubExprs[1] = OpCoawait;
+ }
+
+ DependentCoawaitExpr(EmptyShell Empty)
+ : Expr(DependentCoawaitExprClass, Empty) {}
+
+ Expr *getOperand() const { return cast<Expr>(SubExprs[0]); }
+ UnresolvedLookupExpr *getOperatorCoawaitLookup() const {
+ return cast<UnresolvedLookupExpr>(SubExprs[1]);
+ }
+ SourceLocation getKeywordLoc() const { return KeywordLoc; }
+
+ SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getOperand()->getLocEnd();
+ }
+
+ child_range children() { return child_range(SubExprs, SubExprs + 2); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DependentCoawaitExprClass;
+ }
+};
+
/// \brief Represents a 'co_yield' expression.
class CoyieldExpr : public CoroutineSuspendExpr {
friend class ASTStmtReader;
public:
CoyieldExpr(SourceLocation CoyieldLoc, Expr *Operand, Expr *Ready,
- Expr *Suspend, Expr *Resume)
+ Expr *Suspend, Expr *Resume, OpaqueValueExpr *OpaqueValue)
: CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Operand, Ready,
- Suspend, Resume) {}
+ Suspend, Resume, OpaqueValue) {}
CoyieldExpr(SourceLocation CoyieldLoc, QualType Ty, Expr *Operand)
: CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Ty, Operand) {}
CoyieldExpr(EmptyShell Empty)
diff --git a/include/clang/AST/ExternalASTMerger.h b/include/clang/AST/ExternalASTMerger.h
new file mode 100644
index 000000000000..51d0c30ad23b
--- /dev/null
+++ b/include/clang/AST/ExternalASTMerger.h
@@ -0,0 +1,51 @@
+//===--- ExternalASTMerger.h - Merging External AST Interface ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the ExternalASTMerger, which vends a combination of ASTs
+// from several different ASTContext/FileManager pairs
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_EXTERNALASTMERGER_H
+#define LLVM_CLANG_AST_EXTERNALASTMERGER_H
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/ExternalASTSource.h"
+
+namespace clang {
+
+class ExternalASTMerger : public ExternalASTSource {
+public:
+ struct ImporterPair {
+ std::unique_ptr<ASTImporter> Forward;
+ std::unique_ptr<ASTImporter> Reverse;
+ };
+
+private:
+ std::vector<ImporterPair> Importers;
+
+public:
+ struct ImporterEndpoint {
+ ASTContext &AST;
+ FileManager &FM;
+ };
+ ExternalASTMerger(const ImporterEndpoint &Target,
+ llvm::ArrayRef<ImporterEndpoint> Sources);
+
+ bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) override;
+
+ void
+ FindExternalLexicalDecls(const DeclContext *DC,
+ llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
+ SmallVectorImpl<Decl *> &Result) override;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 2e99f395f495..d8dd18ecb8d3 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -16,6 +16,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclBase.h"
+#include "clang/Basic/Module.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
@@ -149,26 +150,30 @@ public:
StringRef PCHModuleName;
StringRef Path;
StringRef ASTFile;
- uint64_t Signature = 0;
+ ASTFileSignature Signature;
const Module *ClangModule = nullptr;
public:
ASTSourceDescriptor(){};
ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile,
- uint64_t Signature)
+ ASTFileSignature Signature)
: PCHModuleName(std::move(Name)), Path(std::move(Path)),
ASTFile(std::move(ASTFile)), Signature(Signature){};
ASTSourceDescriptor(const Module &M);
std::string getModuleName() const;
StringRef getPath() const { return Path; }
StringRef getASTFile() const { return ASTFile; }
- uint64_t getSignature() const { return Signature; }
+ ASTFileSignature getSignature() const { return Signature; }
const Module *getModuleOrNull() const { return ClangModule; }
};
/// Return a descriptor for the corresponding module, if one exists.
virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID);
+ enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
+
+ virtual ExtKind hasExternalDefinitions(const Decl *D);
+
/// \brief Finds all declarations lexically contained within the given
/// DeclContext, after applying an optional filter predicate.
///
diff --git a/include/clang/AST/ODRHash.h b/include/clang/AST/ODRHash.h
new file mode 100644
index 000000000000..9af8488fca10
--- /dev/null
+++ b/include/clang/AST/ODRHash.h
@@ -0,0 +1,84 @@
+//===-- ODRHash.h - Hashing to diagnose ODR failures ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the ODRHash class, which calculates
+/// a hash based on AST nodes, which is stable across different runs.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TemplateBase.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+class Decl;
+class IdentifierInfo;
+class NestedNameSpecifer;
+class Stmt;
+class TemplateParameterList;
+
+// ODRHash is used to calculate a hash based on AST node contents that
+// does not rely on pointer addresses. This allows the hash to not vary
+// between runs and is usable to detect ODR problems in modules. To use,
+// construct an ODRHash object, then call Add* methods over the nodes that
+// need to be hashed. Then call CalculateHash to get the hash value.
+// Typically, only one Add* call is needed. clear can be called to reuse the
+// object.
+class ODRHash {
+ // Use DenseMaps to convert between Decl and Type pointers and an index value.
+ llvm::DenseMap<const Decl*, unsigned> DeclMap;
+ llvm::DenseMap<const Type*, unsigned> TypeMap;
+
+ // Save space by processing bools at the end.
+ llvm::SmallVector<bool, 128> Bools;
+
+ llvm::FoldingSetNodeID ID;
+
+public:
+ ODRHash() {}
+
+ // Use this for ODR checking classes between modules. This method compares
+ // more information than the AddDecl class.
+ void AddCXXRecordDecl(const CXXRecordDecl *Record);
+
+ // Process SubDecls of the main Decl. This method calls the DeclVisitor
+ // while AddDecl does not.
+ void AddSubDecl(const Decl *D);
+
+ // Reset the object for reuse.
+ void clear();
+
+ // Add booleans to ID and uses it to calculate the hash.
+ unsigned CalculateHash();
+
+ // Add AST nodes that need to be processed.
+ void AddDecl(const Decl *D);
+ void AddType(const Type *T);
+ void AddQualType(QualType T);
+ void AddStmt(const Stmt *S);
+ void AddIdentifierInfo(const IdentifierInfo *II);
+ void AddNestedNameSpecifier(const NestedNameSpecifier *NNS);
+ void AddTemplateName(TemplateName Name);
+ void AddDeclarationName(DeclarationName Name);
+ void AddTemplateArgument(TemplateArgument TA);
+ void AddTemplateParameterList(const TemplateParameterList *TPL);
+
+ // Save booleans until the end to lower the size of data to process.
+ void AddBoolean(bool value);
+
+ static bool isWhitelistedDecl(const Decl* D, const CXXRecordDecl *Record);
+};
+
+} // end namespace clang
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 3e4c4bc7ea40..f977e63e04f6 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -76,10 +76,17 @@ class OMPClauseWithPreInit {
friend class OMPClauseReader;
/// Pre-initialization statement for the clause.
Stmt *PreInit;
+ /// Region that captures the associated stmt.
+ OpenMPDirectiveKind CaptureRegion;
+
protected:
/// Set pre-initialization statement for the clause.
- void setPreInitStmt(Stmt *S) { PreInit = S; }
- OMPClauseWithPreInit(const OMPClause *This) : PreInit(nullptr) {
+ void setPreInitStmt(Stmt *S, OpenMPDirectiveKind ThisRegion = OMPD_unknown) {
+ PreInit = S;
+ CaptureRegion = ThisRegion;
+ }
+ OMPClauseWithPreInit(const OMPClause *This)
+ : PreInit(nullptr), CaptureRegion(OMPD_unknown) {
assert(get(This) && "get is not tuned for pre-init.");
}
@@ -88,6 +95,8 @@ public:
const Stmt *getPreInitStmt() const { return PreInit; }
/// Get pre-initialization statement for the clause.
Stmt *getPreInitStmt() { return PreInit; }
+ /// Get capture region for the stmt in the clause.
+ OpenMPDirectiveKind getCaptureRegion() { return CaptureRegion; }
static OMPClauseWithPreInit *get(OMPClause *C);
static const OMPClauseWithPreInit *get(const OMPClause *C);
};
@@ -194,7 +203,7 @@ public:
/// In this example directive '#pragma omp parallel' has simple 'if' clause with
/// condition 'a > 5' and directive name modifier 'parallel'.
///
-class OMPIfClause : public OMPClause {
+class OMPIfClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -225,26 +234,31 @@ public:
///
/// \param NameModifier [OpenMP 4.1] Directive name modifier of clause.
/// \param Cond Condition of the clause.
+ /// \param HelperCond Helper condition for the clause.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param NameModifierLoc Location of directive name modifier.
/// \param ColonLoc [OpenMP 4.1] Location of ':'.
/// \param EndLoc Ending location of the clause.
///
- OMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Cond,
- SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation NameModifierLoc, SourceLocation ColonLoc,
- SourceLocation EndLoc)
- : OMPClause(OMPC_if, StartLoc, EndLoc), LParenLoc(LParenLoc),
- Condition(Cond), ColonLoc(ColonLoc), NameModifier(NameModifier),
- NameModifierLoc(NameModifierLoc) {}
+ OMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Cond, Stmt *HelperCond,
+ OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation NameModifierLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_if, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), Condition(Cond), ColonLoc(ColonLoc),
+ NameModifier(NameModifier), NameModifierLoc(NameModifierLoc) {
+ setPreInitStmt(HelperCond, CaptureRegion);
+ }
/// \brief Build an empty clause.
///
OMPIfClause()
- : OMPClause(OMPC_if, SourceLocation(), SourceLocation()), LParenLoc(),
- Condition(nullptr), ColonLoc(), NameModifier(OMPD_unknown),
- NameModifierLoc() {}
+ : OMPClause(OMPC_if, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this), LParenLoc(), Condition(nullptr), ColonLoc(),
+ NameModifier(OMPD_unknown), NameModifierLoc() {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@@ -331,7 +345,7 @@ public:
/// In this example directive '#pragma omp parallel' has simple 'num_threads'
/// clause with number of threads '6'.
///
-class OMPNumThreadsClause : public OMPClause {
+class OMPNumThreadsClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -346,20 +360,29 @@ public:
/// \brief Build 'num_threads' clause with condition \a NumThreads.
///
/// \param NumThreads Number of threads for the construct.
+ /// \param HelperNumThreads Helper Number of threads for the construct.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
///
- OMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc)
- : OMPClause(OMPC_num_threads, StartLoc, EndLoc), LParenLoc(LParenLoc),
- NumThreads(NumThreads) {}
+ OMPNumThreadsClause(Expr *NumThreads, Stmt *HelperNumThreads,
+ OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_num_threads, StartLoc, EndLoc),
+ OMPClauseWithPreInit(this), LParenLoc(LParenLoc),
+ NumThreads(NumThreads) {
+ setPreInitStmt(HelperNumThreads, CaptureRegion);
+ }
/// \brief Build an empty clause.
///
OMPNumThreadsClause()
: OMPClause(OMPC_num_threads, SourceLocation(), SourceLocation()),
- LParenLoc(SourceLocation()), NumThreads(nullptr) {}
+ OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
+ NumThreads(nullptr) {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@@ -3456,7 +3479,7 @@ public:
/// In this example directive '#pragma omp teams' has clause 'num_teams'
/// with single expression 'n'.
///
-class OMPNumTeamsClause : public OMPClause {
+class OMPNumTeamsClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -3472,20 +3495,27 @@ public:
/// \brief Build 'num_teams' clause.
///
/// \param E Expression associated with this clause.
+ /// \param HelperE Helper Expression associated with this clause.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
///
- OMPNumTeamsClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
+ OMPNumTeamsClause(Expr *E, Stmt *HelperE, OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
- : OMPClause(OMPC_num_teams, StartLoc, EndLoc), LParenLoc(LParenLoc),
- NumTeams(E) {}
+ : OMPClause(OMPC_num_teams, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), NumTeams(E) {
+ setPreInitStmt(HelperE, CaptureRegion);
+ }
/// \brief Build an empty clause.
///
OMPNumTeamsClause()
- : OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()),
- LParenLoc(SourceLocation()), NumTeams(nullptr) {}
+ : OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
+ NumTeams(nullptr) {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
/// \brief Returns the location of '('.
@@ -3511,7 +3541,7 @@ public:
/// In this example directive '#pragma omp teams' has clause 'thread_limit'
/// with single expression 'n'.
///
-class OMPThreadLimitClause : public OMPClause {
+class OMPThreadLimitClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -3527,20 +3557,28 @@ public:
/// \brief Build 'thread_limit' clause.
///
/// \param E Expression associated with this clause.
+ /// \param HelperE Helper Expression associated with this clause.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
///
- OMPThreadLimitClause(Expr *E, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc)
- : OMPClause(OMPC_thread_limit, StartLoc, EndLoc), LParenLoc(LParenLoc),
- ThreadLimit(E) {}
+ OMPThreadLimitClause(Expr *E, Stmt *HelperE,
+ OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_thread_limit, StartLoc, EndLoc),
+ OMPClauseWithPreInit(this), LParenLoc(LParenLoc), ThreadLimit(E) {
+ setPreInitStmt(HelperE, CaptureRegion);
+ }
/// \brief Build an empty clause.
///
OMPThreadLimitClause()
: OMPClause(OMPC_thread_limit, SourceLocation(), SourceLocation()),
- LParenLoc(SourceLocation()), ThreadLimit(nullptr) {}
+ OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
+ ThreadLimit(nullptr) {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
/// \brief Returns the location of '('.
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 10a930abe6fb..1b5850a05b37 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -774,6 +774,11 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
break;
+ case DeclarationName::CXXDeductionGuideName:
+ TRY_TO(TraverseTemplateName(
+ TemplateName(NameInfo.getName().getCXXDeductionGuideTemplate())));
+ break;
+
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
@@ -1008,6 +1013,10 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
})
DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
+DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
+ TRY_TO(TraverseTemplateName(T->getTemplateName()));
+ TRY_TO(TraverseType(T->getDeducedType()));
+})
DEF_TRAVERSE_TYPE(RecordType, {})
DEF_TRAVERSE_TYPE(EnumType, {})
@@ -1232,6 +1241,11 @@ DEF_TRAVERSE_TYPELOC(AutoType, {
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
})
+DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
+ TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
+ TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
+})
+
DEF_TRAVERSE_TYPELOC(RecordType, {})
DEF_TRAVERSE_TYPELOC(EnumType, {})
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
@@ -1932,6 +1946,13 @@ DEF_TRAVERSE_DECL(FunctionDecl, {
ReturnValue = TraverseFunctionHelper(D);
})
+DEF_TRAVERSE_DECL(CXXDeductionGuideDecl, {
+ // We skip decls_begin/decls_end, which are already covered by
+ // TraverseFunctionHelper().
+ ShouldVisitChildren = false;
+ ReturnValue = TraverseFunctionHelper(D);
+})
+
DEF_TRAVERSE_DECL(CXXMethodDecl, {
// We skip decls_begin/decls_end, which are already covered by
// TraverseFunctionHelper().
@@ -2495,6 +2516,12 @@ DEF_TRAVERSE_STMT(CoawaitExpr, {
ShouldVisitChildren = false;
}
})
+DEF_TRAVERSE_STMT(DependentCoawaitExpr, {
+ if (!getDerived().shouldVisitImplicitCode()) {
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
+ ShouldVisitChildren = false;
+ }
+})
DEF_TRAVERSE_STMT(CoyieldExpr, {
if (!getDerived().shouldVisitImplicitCode()) {
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
@@ -2711,6 +2738,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPClauseWithPostUpdate(
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPIfClause(OMPIfClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getCondition()));
return true;
}
@@ -2724,6 +2752,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPFinalClause(OMPFinalClause *C) {
template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getNumThreads()));
return true;
}
@@ -2993,6 +3022,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
OMPNumTeamsClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getNumTeams()));
return true;
}
@@ -3000,6 +3030,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPThreadLimitClause(
OMPThreadLimitClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getThreadLimit()));
return true;
}
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index e28675d6a828..c210bd1cec2e 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -39,6 +39,7 @@ namespace clang {
class Expr;
class IdentifierInfo;
class LabelDecl;
+ class ODRHash;
class ParmVarDecl;
class PrinterHelper;
struct PrintingPolicy;
@@ -126,13 +127,13 @@ protected:
unsigned : NumStmtBits;
unsigned ValueKind : 2;
- unsigned ObjectKind : 2;
+ unsigned ObjectKind : 3;
unsigned TypeDependent : 1;
unsigned ValueDependent : 1;
unsigned InstantiationDependent : 1;
unsigned ContainsUnexpandedParameterPack : 1;
};
- enum { NumExprBits = 16 };
+ enum { NumExprBits = 17 };
class CharacterLiteralBitfields {
friend class CharacterLiteral;
@@ -252,6 +253,14 @@ protected:
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
};
+ class CoawaitExprBitfields {
+ friend class CoawaitExpr;
+
+ unsigned : NumExprBits;
+
+ unsigned IsImplicit : 1;
+ };
+
union {
StmtBitfields StmtBits;
CompoundStmtBitfields CompoundStmtBits;
@@ -268,6 +277,7 @@ protected:
ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
InitListExprBitfields InitListExprBits;
TypeTraitExprBitfields TypeTraitExprBits;
+ CoawaitExprBitfields CoawaitBits;
};
friend class ASTStmtReader;
@@ -340,6 +350,8 @@ protected:
public:
Stmt(StmtClass SC) {
+ static_assert(sizeof(*this) == sizeof(void *),
+ "changing bitfields changed sizeof(Stmt)");
static_assert(sizeof(*this) % alignof(void *) == 0,
"Insufficient alignment!");
StmtBits.sClass = SC;
@@ -436,6 +448,15 @@ public:
/// written in the source.
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
bool Canonical) const;
+
+ /// \brief Calculate a unique representation for a statement that is
+ /// stable across compiler invocations.
+ ///
+ /// \param ID profile information will be stored in ID.
+ ///
+ /// \param Hash an ODRHash object which will be called where pointers would
+ /// have been used in the Profile function.
+ void ProcessODRHash(llvm::FoldingSetNodeID &ID, ODRHash& Hash) const;
};
/// DeclStmt - Adaptor class for mixing declarations with statements and
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 8eef34cb21b3..56bfce987f5b 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -296,7 +296,9 @@ public:
/// \brief Represents the body of a coroutine. This wraps the normal function
/// body and holds the additional semantic context required to set up and tear
/// down the coroutine frame.
-class CoroutineBodyStmt : public Stmt {
+class CoroutineBodyStmt final
+ : public Stmt,
+ private llvm::TrailingObjects<CoroutineBodyStmt, Stmt *> {
enum SubStmt {
Body, ///< The body of the coroutine.
Promise, ///< The promise statement.
@@ -307,65 +309,100 @@ class CoroutineBodyStmt : public Stmt {
Allocate, ///< Coroutine frame memory allocation.
Deallocate, ///< Coroutine frame memory deallocation.
ReturnValue, ///< Return value for thunk function.
+ ReturnStmtOnAllocFailure, ///< Return statement if allocation failed.
FirstParamMove ///< First offset for move construction of parameter copies.
};
- Stmt *SubStmts[SubStmt::FirstParamMove];
+ unsigned NumParams;
friend class ASTStmtReader;
+ friend TrailingObjects;
+
+ Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); }
+
+ Stmt *const *getStoredStmts() const { return getTrailingObjects<Stmt *>(); }
+
+public:
+
+ struct CtorArgs {
+ Stmt *Body = nullptr;
+ Stmt *Promise = nullptr;
+ Expr *InitialSuspend = nullptr;
+ Expr *FinalSuspend = nullptr;
+ Stmt *OnException = nullptr;
+ Stmt *OnFallthrough = nullptr;
+ Expr *Allocate = nullptr;
+ Expr *Deallocate = nullptr;
+ Stmt *ReturnValue = nullptr;
+ Stmt *ReturnStmtOnAllocFailure = nullptr;
+ ArrayRef<Stmt *> ParamMoves;
+ };
+
+private:
+
+ CoroutineBodyStmt(CtorArgs const& Args);
+
public:
- CoroutineBodyStmt(Stmt *Body, Stmt *Promise, Stmt *InitSuspend,
- Stmt *FinalSuspend, Stmt *OnException, Stmt *OnFallthrough,
- Expr *Allocate, Stmt *Deallocate,
- Expr *ReturnValue, ArrayRef<Expr *> ParamMoves)
- : Stmt(CoroutineBodyStmtClass) {
- SubStmts[CoroutineBodyStmt::Body] = Body;
- SubStmts[CoroutineBodyStmt::Promise] = Promise;
- SubStmts[CoroutineBodyStmt::InitSuspend] = InitSuspend;
- SubStmts[CoroutineBodyStmt::FinalSuspend] = FinalSuspend;
- SubStmts[CoroutineBodyStmt::OnException] = OnException;
- SubStmts[CoroutineBodyStmt::OnFallthrough] = OnFallthrough;
- SubStmts[CoroutineBodyStmt::Allocate] = Allocate;
- SubStmts[CoroutineBodyStmt::Deallocate] = Deallocate;
- SubStmts[CoroutineBodyStmt::ReturnValue] = ReturnValue;
- // FIXME: Tail-allocate space for parameter move expressions and store them.
- assert(ParamMoves.empty() && "not implemented yet");
+ static CoroutineBodyStmt *Create(const ASTContext &C, CtorArgs const &Args);
+
+ bool hasDependentPromiseType() const {
+ return getPromiseDecl()->getType()->isDependentType();
}
/// \brief Retrieve the body of the coroutine as written. This will be either
/// a CompoundStmt or a TryStmt.
Stmt *getBody() const {
- return SubStmts[SubStmt::Body];
+ return getStoredStmts()[SubStmt::Body];
}
- Stmt *getPromiseDeclStmt() const { return SubStmts[SubStmt::Promise]; }
+ Stmt *getPromiseDeclStmt() const {
+ return getStoredStmts()[SubStmt::Promise];
+ }
VarDecl *getPromiseDecl() const {
return cast<VarDecl>(cast<DeclStmt>(getPromiseDeclStmt())->getSingleDecl());
}
- Stmt *getInitSuspendStmt() const { return SubStmts[SubStmt::InitSuspend]; }
- Stmt *getFinalSuspendStmt() const { return SubStmts[SubStmt::FinalSuspend]; }
+ Stmt *getInitSuspendStmt() const {
+ return getStoredStmts()[SubStmt::InitSuspend];
+ }
+ Stmt *getFinalSuspendStmt() const {
+ return getStoredStmts()[SubStmt::FinalSuspend];
+ }
- Stmt *getExceptionHandler() const { return SubStmts[SubStmt::OnException]; }
+ Stmt *getExceptionHandler() const {
+ return getStoredStmts()[SubStmt::OnException];
+ }
Stmt *getFallthroughHandler() const {
- return SubStmts[SubStmt::OnFallthrough];
+ return getStoredStmts()[SubStmt::OnFallthrough];
}
- Expr *getAllocate() const { return cast<Expr>(SubStmts[SubStmt::Allocate]); }
- Stmt *getDeallocate() const { return SubStmts[SubStmt::Deallocate]; }
+ Expr *getAllocate() const {
+ return cast_or_null<Expr>(getStoredStmts()[SubStmt::Allocate]);
+ }
+ Expr *getDeallocate() const {
+ return cast_or_null<Expr>(getStoredStmts()[SubStmt::Deallocate]);
+ }
Expr *getReturnValueInit() const {
- return cast<Expr>(SubStmts[SubStmt::ReturnValue]);
+ return cast_or_null<Expr>(getStoredStmts()[SubStmt::ReturnValue]);
+ }
+ Stmt *getReturnStmtOnAllocFailure() const {
+ return getStoredStmts()[SubStmt::ReturnStmtOnAllocFailure];
+ }
+ ArrayRef<Stmt const *> getParamMoves() const {
+ return {getStoredStmts() + SubStmt::FirstParamMove, NumParams};
}
SourceLocation getLocStart() const LLVM_READONLY {
- return getBody()->getLocStart();
+ return getBody() ? getBody()->getLocStart()
+ : getPromiseDecl()->getLocStart();
}
SourceLocation getLocEnd() const LLVM_READONLY {
- return getBody()->getLocEnd();
+ return getBody() ? getBody()->getLocEnd() : getPromiseDecl()->getLocEnd();
}
child_range children() {
- return child_range(SubStmts, SubStmts + SubStmt::FirstParamMove);
+ return child_range(getStoredStmts(),
+ getStoredStmts() + SubStmt::FirstParamMove + NumParams);
}
static bool classof(const Stmt *T) {
@@ -390,10 +427,14 @@ class CoreturnStmt : public Stmt {
enum SubStmt { Operand, PromiseCall, Count };
Stmt *SubStmts[SubStmt::Count];
+ bool IsImplicit : 1;
+
friend class ASTStmtReader;
public:
- CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall)
- : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc) {
+ CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall,
+ bool IsImplicit = false)
+ : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc),
+ IsImplicit(IsImplicit) {
SubStmts[SubStmt::Operand] = Operand;
SubStmts[SubStmt::PromiseCall] = PromiseCall;
}
@@ -411,6 +452,9 @@ public:
return static_cast<Expr*>(SubStmts[PromiseCall]);
}
+ bool isImplicit() const { return IsImplicit; }
+ void setIsImplicit(bool value = true) { IsImplicit = value; }
+
SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; }
SourceLocation getLocEnd() const LLVM_READONLY {
return getOperand() ? getOperand()->getLocEnd() : getLocStart();
diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h
index 81f8ad4344a9..5d3bce8d83ba 100644
--- a/include/clang/AST/StmtIterator.h
+++ b/include/clang/AST/StmtIterator.h
@@ -118,6 +118,8 @@ public:
REFERENCE operator->() const { return operator*(); }
};
+struct ConstStmtIterator;
+
struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {}
@@ -128,6 +130,13 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
StmtIterator(const VariableArrayType *t)
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
+
+private:
+ StmtIterator(const StmtIteratorBase &RHS)
+ : StmtIteratorImpl<StmtIterator, Stmt *&>(RHS) {}
+
+ inline friend StmtIterator
+ cast_away_const(const ConstStmtIterator &RHS);
};
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
@@ -137,8 +146,15 @@ struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
ConstStmtIterator(const StmtIterator& RHS) :
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
+
+ ConstStmtIterator(Stmt * const *S)
+ : StmtIteratorImpl<ConstStmtIterator, const Stmt *>(
+ const_cast<Stmt **>(S)) {}
};
+inline StmtIterator cast_away_const(const ConstStmtIterator &RHS) {
+ return RHS;
+}
} // end namespace clang
#endif
diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h
index ec532ecd5881..13af142ca3ab 100644
--- a/include/clang/AST/StmtOpenMP.h
+++ b/include/clang/AST/StmtOpenMP.h
@@ -198,6 +198,26 @@ public:
return const_cast<Stmt *>(*child_begin());
}
+ /// \brief Returns the captured statement associated with the
+ /// component region within the (combined) directive.
+ //
+ // \param RegionKind Component region kind.
+ CapturedStmt *getCapturedStmt(OpenMPDirectiveKind RegionKind) const {
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, getDirectiveKind());
+ assert(std::any_of(
+ CaptureRegions.begin(), CaptureRegions.end(),
+ [=](const OpenMPDirectiveKind K) { return K == RegionKind; }) &&
+ "RegionKind not found in OpenMP CaptureRegions.");
+ auto *CS = cast<CapturedStmt>(getAssociatedStmt());
+ for (auto ThisCaptureRegion : CaptureRegions) {
+ if (ThisCaptureRegion == RegionKind)
+ return CS;
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ }
+ llvm_unreachable("Incorrect RegionKind specified for directive.");
+ }
+
OpenMPDirectiveKind getDirectiveKind() const { return Kind; }
static bool classof(const Stmt *S) {
@@ -304,6 +324,11 @@ class OMPLoopDirective : public OMPExecutableDirective {
/// allocated: loop counters, their updates and final values.
/// PrevLowerBound and PrevUpperBound are used to communicate blocking
/// information in composite constructs which require loop blocking
+ /// DistInc is used to generate the increment expression for the distribute
+ /// loop when combined with a further nested loop
+ /// PrevEnsureUpperBound is used as the EnsureUpperBound expression for the
+ /// for loop when combined with a previous distribute loop in the same pragma
+ /// (e.g. 'distribute parallel for')
///
enum {
AssociatedStmtOffset = 0,
@@ -319,7 +344,7 @@ class OMPLoopDirective : public OMPExecutableDirective {
// specify the offset to the end (and start of the following counters/
// updates/finals arrays).
DefaultEnd = 9,
- // The following 7 exprs are used by worksharing loops only.
+ // The following 12 exprs are used by worksharing and distribute loops only.
IsLastIterVariableOffset = 9,
LowerBoundVariableOffset = 10,
UpperBoundVariableOffset = 11,
@@ -330,9 +355,11 @@ class OMPLoopDirective : public OMPExecutableDirective {
NumIterationsOffset = 16,
PrevLowerBoundVariableOffset = 17,
PrevUpperBoundVariableOffset = 18,
+ DistIncOffset = 19,
+ PrevEnsureUpperBoundOffset = 20,
// Offset to the end (and start of the following counters/updates/finals
// arrays) for worksharing loop directives.
- WorksharingEnd = 19,
+ WorksharingEnd = 21,
};
/// \brief Get the counters storage.
@@ -501,6 +528,20 @@ protected:
"expected worksharing loop directive");
*std::next(child_begin(), PrevUpperBoundVariableOffset) = PrevUB;
}
+ void setDistInc(Expr *DistInc) {
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), DistIncOffset) = DistInc;
+ }
+ void setPrevEnsureUpperBound(Expr *PrevEUB) {
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
+ "expected worksharing loop directive");
+ *std::next(child_begin(), PrevEnsureUpperBoundOffset) = PrevEUB;
+ }
void setCounters(ArrayRef<Expr *> A);
void setPrivateCounters(ArrayRef<Expr *> A);
void setInits(ArrayRef<Expr *> A);
@@ -535,7 +576,7 @@ public:
Expr *UB;
/// \brief Stride - local variable passed to runtime.
Expr *ST;
- /// \brief EnsureUpperBound -- expression LB = min(LB, NumIterations).
+ /// \brief EnsureUpperBound -- expression UB = min(UB, NumIterations).
Expr *EUB;
/// \brief Update of LowerBound for statically sheduled 'omp for' loops.
Expr *NLB;
@@ -547,6 +588,16 @@ public:
/// \brief PreviousUpperBound - local variable passed to runtime in the
/// enclosing schedule or null if that does not apply.
Expr *PrevUB;
+ /// \brief DistInc - increment expression for distribute loop when found
+ /// combined with a further loop level (e.g. in 'distribute parallel for')
+ /// expression IV = IV + ST
+ Expr *DistInc;
+ /// \brief PrevEUB - expression similar to EUB but to be used when loop
+ /// scheduling uses PrevLB and PrevUB (e.g. in 'distribute parallel for'
+ /// when ensuring that the UB is either the calculated UB by the runtime or
+ /// the end of the assigned distribute chunk)
+ /// expression UB = min (UB, PrevUB)
+ Expr *PrevEUB;
/// \brief Counters Loop counters.
SmallVector<Expr *, 4> Counters;
/// \brief PrivateCounters Loop counters.
@@ -588,6 +639,8 @@ public:
NumIterations = nullptr;
PrevLB = nullptr;
PrevUB = nullptr;
+ DistInc = nullptr;
+ PrevEUB = nullptr;
Counters.resize(Size);
PrivateCounters.resize(Size);
Inits.resize(Size);
@@ -719,6 +772,22 @@ public:
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), PrevUpperBoundVariableOffset)));
}
+ Expr *getDistInc() const {
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), DistIncOffset)));
+ }
+ Expr *getPrevEnsureUpperBound() const {
+ assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
+ isOpenMPTaskLoopDirective(getDirectiveKind()) ||
+ isOpenMPDistributeDirective(getDirectiveKind())) &&
+ "expected worksharing loop directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), PrevEnsureUpperBoundOffset)));
+ }
const Stmt *getBody() const {
// This relies on the loop form is already checked by Sema.
Stmt *Body = getAssociatedStmt()->IgnoreContainers(true);
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 7f289862578d..84fbcda6e087 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -119,10 +119,7 @@ private:
public:
/// \brief Construct an empty, invalid template argument.
- TemplateArgument() {
- TypeOrValue.Kind = Null;
- TypeOrValue.V = 0;
- }
+ constexpr TemplateArgument() : TypeOrValue({Null, 0}) {}
/// \brief Construct a template type argument.
TemplateArgument(QualType T, bool isNullPtr = false) {
@@ -388,8 +385,8 @@ private:
};
public:
- TemplateArgumentLocInfo();
-
+ constexpr TemplateArgumentLocInfo() : Template({nullptr, nullptr, 0, 0}) {}
+
TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {}
TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
@@ -433,7 +430,7 @@ class TemplateArgumentLoc {
TemplateArgumentLocInfo LocInfo;
public:
- TemplateArgumentLoc() {}
+ constexpr TemplateArgumentLoc() {}
TemplateArgumentLoc(const TemplateArgument &Argument,
TemplateArgumentLocInfo Opaque)
@@ -578,6 +575,7 @@ struct ASTTemplateArgumentListInfo final
TemplateArgumentLoc> {
private:
friend TrailingObjects;
+ friend class ASTNodeImporter;
ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List);
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index a50e054f9b28..bd30aad10f27 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -333,6 +333,20 @@ public:
bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
+ /// Get the address space attribute value to be printed by diagnostics.
+ unsigned getAddressSpaceAttributePrintValue() const {
+ auto Addr = getAddressSpace();
+ // This function is not supposed to be used with language specific
+ // address spaces. If that happens, the diagnostic message should consider
+ // printing the QualType instead of the address space value.
+ assert(Addr == 0 || Addr >= LangAS::Count);
+ if (Addr)
+ return Addr - LangAS::Count;
+ // TODO: The diagnostic messages where Addr may be 0 should be fixed
+ // since it cannot differentiate the situation where 0 denotes the default
+ // address space or user specified __attribute__((address_space(0))).
+ return 0;
+ }
void setAddressSpace(unsigned space) {
assert(space <= MaxAddressSpace);
Mask = (Mask & ~AddressSpaceMask)
@@ -1020,6 +1034,9 @@ public:
return getQualifiers().hasStrongOrWeakObjCLifetime();
}
+ // true when Type is objc's weak and weak is enabled but ARC isn't.
+ bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const;
+
enum DestructionKind {
DK_none,
DK_cxx_destructor,
@@ -1744,7 +1761,6 @@ public:
bool isEventT() const; // OpenCL event_t
bool isClkEventT() const; // OpenCL clk_event_t
bool isQueueT() const; // OpenCL queue_t
- bool isNDRangeT() const; // OpenCL ndrange_t
bool isReserveIDT() const; // OpenCL reserve_id_t
bool isPipeType() const; // OpenCL pipe type
@@ -1785,7 +1801,8 @@ public:
}
/// \brief Determine whether this type is an undeduced type, meaning that
- /// it somehow involves a C++11 'auto' type which has not yet been deduced.
+ /// it somehow involves a C++11 'auto' type or similar which has not yet been
+ /// deduced.
bool isUndeducedType() const;
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
@@ -1862,10 +1879,22 @@ public:
/// not refer to a CXXRecordDecl, returns NULL.
const CXXRecordDecl *getPointeeCXXRecordDecl() const;
+ /// Get the DeducedType whose type will be deduced for a variable with
+ /// an initializer of this type. This looks through declarators like pointer
+ /// types, but not through decltype or typedefs.
+ DeducedType *getContainedDeducedType() const;
+
/// Get the AutoType whose type will be deduced for a variable with
/// an initializer of this type. This looks through declarators like pointer
/// types, but not through decltype or typedefs.
- AutoType *getContainedAutoType() const;
+ AutoType *getContainedAutoType() const {
+ return dyn_cast_or_null<AutoType>(getContainedDeducedType());
+ }
+
+ /// Determine whether this type was written with a leading 'auto'
+ /// corresponding to a trailing return type (possibly for a nested
+ /// function type within a pointer to function type or similar).
+ bool hasAutoForTrailingReturnType() const;
/// Member-template getAs<specific type>'. Look through sugar for
/// an instance of \<specific type>. This scheme will eventually
@@ -1875,6 +1904,13 @@ public:
/// immediately following this class.
template <typename T> const T *getAs() const;
+ /// Member-template getAsAdjusted<specific type>. Look through specific kinds
+ /// of sugar (parens, attributes, etc) for an instance of \<specific type>.
+ /// This is used when you need to walk over sugar nodes that represent some
+ /// kind of type adjustment from a type that was written as a \<specific type>
+ /// to another type that is still canonically a \<specific type>.
+ template <typename T> const T *getAsAdjusted() const;
+
/// A variant of getAs<> for array types which silently discards
/// qualifiers from the outermost type.
const ArrayType *getAsArrayTypeUnsafe() const;
@@ -2057,7 +2093,7 @@ public:
: Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
/*InstantiationDependent=*/(K == Dependent),
/*VariablyModified=*/false,
- /*Unexpanded paramter pack=*/false) {
+ /*Unexpanded parameter pack=*/false) {
BuiltinTypeBits.Kind = K;
}
@@ -3097,9 +3133,11 @@ public:
class ExtParameterInfo {
enum {
ABIMask = 0x0F,
- IsConsumed = 0x10
+ IsConsumed = 0x10,
+ HasPassObjSize = 0x20,
};
unsigned char Data;
+
public:
ExtParameterInfo() : Data(0) {}
@@ -3128,6 +3166,15 @@ public:
return copy;
}
+ bool hasPassObjectSize() const {
+ return Data & HasPassObjSize;
+ }
+ ExtParameterInfo withHasPassObjectSize() const {
+ ExtParameterInfo Copy = *this;
+ Copy.Data |= HasPassObjSize;
+ return Copy;
+ }
+
unsigned char getOpaqueValue() const { return Data; }
static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
ExtParameterInfo result;
@@ -4089,43 +4136,41 @@ public:
}
};
-/// \brief Represents a C++11 auto or C++14 decltype(auto) type.
+/// \brief Common base class for placeholders for types that get replaced by
+/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
+/// class template types, and (eventually) constrained type names from the C++
+/// Concepts TS.
///
/// These types are usually a placeholder for a deduced type. However, before
/// the initializer is attached, or (usually) if the initializer is
-/// type-dependent, there is no deduced type and an auto type is canonical. In
+/// type-dependent, there is no deduced type and the type is canonical. In
/// the latter case, it is also a dependent type.
-class AutoType : public Type, public llvm::FoldingSetNode {
- AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent)
- : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
- /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
- /*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
- if (!DeducedType.isNull()) {
- if (DeducedType->isDependentType())
+class DeducedType : public Type {
+protected:
+ DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent,
+ bool IsInstantiationDependent, bool ContainsParameterPack)
+ : Type(TC,
+ // FIXME: Retain the sugared deduced type?
+ DeducedAsType.isNull() ? QualType(this, 0)
+ : DeducedAsType.getCanonicalType(),
+ IsDependent, IsInstantiationDependent,
+ /*VariablyModified=*/false, ContainsParameterPack) {
+ if (!DeducedAsType.isNull()) {
+ if (DeducedAsType->isDependentType())
setDependent();
- if (DeducedType->isInstantiationDependentType())
+ if (DeducedAsType->isInstantiationDependentType())
setInstantiationDependent();
- if (DeducedType->containsUnexpandedParameterPack())
+ if (DeducedAsType->containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
}
- AutoTypeBits.Keyword = (unsigned)Keyword;
}
- friend class ASTContext; // ASTContext creates these
-
public:
- bool isDecltypeAuto() const {
- return getKeyword() == AutoTypeKeyword::DecltypeAuto;
- }
- AutoTypeKeyword getKeyword() const {
- return (AutoTypeKeyword)AutoTypeBits.Keyword;
- }
-
bool isSugared() const { return !isCanonicalUnqualified(); }
QualType desugar() const { return getCanonicalTypeInternal(); }
- /// \brief Get the type deduced for this auto type, or null if it's either
- /// not been deduced or was deduced to a dependent type.
+ /// \brief Get the type deduced for this placeholder type, or null if it's
+ /// either not been deduced or was deduced to a dependent type.
QualType getDeducedType() const {
return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType();
}
@@ -4133,6 +4178,31 @@ public:
return !isCanonicalUnqualified() || isDependentType();
}
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Auto ||
+ T->getTypeClass() == DeducedTemplateSpecialization;
+ }
+};
+
+/// \brief Represents a C++11 auto or C++14 decltype(auto) type.
+class AutoType : public DeducedType, public llvm::FoldingSetNode {
+ AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
+ bool IsDeducedAsDependent)
+ : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
+ IsDeducedAsDependent, /*ContainsPack=*/false) {
+ AutoTypeBits.Keyword = (unsigned)Keyword;
+ }
+
+ friend class ASTContext; // ASTContext creates these
+
+public:
+ bool isDecltypeAuto() const {
+ return getKeyword() == AutoTypeKeyword::DecltypeAuto;
+ }
+ AutoTypeKeyword getKeyword() const {
+ return (AutoTypeKeyword)AutoTypeBits.Keyword;
+ }
+
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getDeducedType(), getKeyword(), isDependentType());
}
@@ -4149,6 +4219,43 @@ public:
}
};
+/// \brief Represents a C++17 deduced template specialization type.
+class DeducedTemplateSpecializationType : public DeducedType,
+ public llvm::FoldingSetNode {
+ /// The name of the template whose arguments will be deduced.
+ TemplateName Template;
+
+ DeducedTemplateSpecializationType(TemplateName Template,
+ QualType DeducedAsType,
+ bool IsDeducedAsDependent)
+ : DeducedType(DeducedTemplateSpecialization, DeducedAsType,
+ IsDeducedAsDependent || Template.isDependent(),
+ IsDeducedAsDependent || Template.isInstantiationDependent(),
+ Template.containsUnexpandedParameterPack()),
+ Template(Template) {}
+
+ friend class ASTContext; // ASTContext creates these
+
+public:
+ /// Retrieve the name of the template that we are deducing.
+ TemplateName getTemplateName() const { return Template;}
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getTemplateName(), getDeducedType(), isDependentType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template,
+ QualType Deduced, bool IsDependent) {
+ Template.Profile(ID);
+ ID.AddPointer(Deduced.getAsOpaquePtr());
+ ID.AddBoolean(IsDependent);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DeducedTemplateSpecialization;
+ }
+};
+
/// \brief Represents a type template specialization; the template
/// must be a class template, a type alias template, or a template
/// template parameter. A template which cannot be resolved to one of
@@ -4345,6 +4452,9 @@ public:
const TemplateSpecializationType *getInjectedTST() const {
return cast<TemplateSpecializationType>(InjectedType.getTypePtr());
}
+ TemplateName getTemplateName() const {
+ return getInjectedTST()->getTemplateName();
+ }
CXXRecordDecl *getDecl() const;
@@ -5718,10 +5828,6 @@ inline bool Type::isQueueT() const {
return isSpecificBuiltinType(BuiltinType::OCLQueue);
}
-inline bool Type::isNDRangeT() const {
- return isSpecificBuiltinType(BuiltinType::OCLNDRange);
-}
-
inline bool Type::isReserveIDT() const {
return isSpecificBuiltinType(BuiltinType::OCLReserveID);
}
@@ -5739,7 +5845,7 @@ inline bool Type::isPipeType() const {
inline bool Type::isOpenCLSpecificType() const {
return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
- isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType();
+ isQueueT() || isReserveIDT() || isPipeType();
}
inline bool Type::isTemplateTypeParmType() const {
@@ -5849,8 +5955,8 @@ inline bool Type::isBooleanType() const {
}
inline bool Type::isUndeducedType() const {
- const AutoType *AT = getContainedAutoType();
- return AT && !AT->isDeduced();
+ auto *DT = getContainedDeducedType();
+ return DT && !DT->isDeduced();
}
/// \brief Determines whether this is a type for which one can define
@@ -5932,6 +6038,38 @@ template <typename T> const T *Type::getAs() const {
return cast<T>(getUnqualifiedDesugaredType());
}
+template <typename T> const T *Type::getAsAdjusted() const {
+ static_assert(!TypeIsArrayType<T>::value, "ArrayType cannot be used with getAsAdjusted!");
+
+ // If this is directly a T type, return it.
+ if (const T *Ty = dyn_cast<T>(this))
+ return Ty;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<T>(CanonicalType))
+ return nullptr;
+
+ // Strip off type adjustments that do not modify the underlying nature of the
+ // type.
+ const Type *Ty = this;
+ while (Ty) {
+ if (const auto *A = dyn_cast<AttributedType>(Ty))
+ Ty = A->getModifiedType().getTypePtr();
+ else if (const auto *E = dyn_cast<ElaboratedType>(Ty))
+ Ty = E->desugar().getTypePtr();
+ else if (const auto *P = dyn_cast<ParenType>(Ty))
+ Ty = P->desugar().getTypePtr();
+ else if (const auto *A = dyn_cast<AdjustedType>(Ty))
+ Ty = A->desugar().getTypePtr();
+ else
+ break;
+ }
+
+ // Just because the canonical type is correct does not mean we can use cast<>,
+ // since we may not have stripped off all the sugar down to the base type.
+ return dyn_cast<T>(Ty);
+}
+
inline const ArrayType *Type::getAsArrayTypeUnsafe() const {
// If this is directly an array type, return it.
if (const ArrayType *arr = dyn_cast<ArrayType>(this))
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 5b7d9e6e3ce1..525f848a9fab 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -70,6 +70,13 @@ public:
return t;
}
+ /// \brief Convert to the specified TypeLoc type, returning a null TypeLoc if
+ /// this TypeLock is not of the desired type. It will consider type
+ /// adjustments from a type that wad written as a T to another type that is
+ /// still canonically a T (ignores parens, attributes, elaborated types, etc).
+ template <typename T>
+ T getAsAdjusted() const;
+
/// The kinds of TypeLocs. Equivalent to the Type::TypeClass enum,
/// except it also defines a Qualified enum that corresponds to the
/// QualifiedLoc class.
@@ -1827,9 +1834,25 @@ public:
}
};
-class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- AutoTypeLoc,
- AutoType> {
+class DeducedTypeLoc
+ : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DeducedTypeLoc,
+ DeducedType> {};
+
+class AutoTypeLoc
+ : public InheritingConcreteTypeLoc<DeducedTypeLoc, AutoTypeLoc, AutoType> {
+};
+
+class DeducedTemplateSpecializationTypeLoc
+ : public InheritingConcreteTypeLoc<DeducedTypeLoc,
+ DeducedTemplateSpecializationTypeLoc,
+ DeducedTemplateSpecializationType> {
+public:
+ SourceLocation getTemplateNameLoc() const {
+ return getNameLoc();
+ }
+ void setTemplateNameLoc(SourceLocation Loc) {
+ setNameLoc(Loc);
+ }
};
struct ElaboratedLocInfo {
@@ -2172,6 +2195,24 @@ public:
QualType getInnerType() const { return this->getTypePtr()->getElementType(); }
};
+
+template <typename T>
+inline T TypeLoc::getAsAdjusted() const {
+ TypeLoc Cur = *this;
+ while (!T::isKind(Cur)) {
+ if (auto PTL = Cur.getAs<ParenTypeLoc>())
+ Cur = PTL.getInnerLoc();
+ else if (auto ATL = Cur.getAs<AttributedTypeLoc>())
+ Cur = ATL.getModifiedLoc();
+ else if (auto ETL = Cur.getAs<ElaboratedTypeLoc>())
+ Cur = ETL.getNamedTypeLoc();
+ else if (auto ATL = Cur.getAs<AdjustedTypeLoc>())
+ Cur = ATL.getOriginalLoc();
+ else
+ break;
+ }
+ return Cur.getAs<T>();
+}
}
#endif
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 27ab21bf7fcb..9d1d09e2cc66 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -96,7 +96,9 @@ DEPENDENT_TYPE(TemplateTypeParm, Type)
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
-TYPE(Auto, Type)
+ABSTRACT_TYPE(Deduced, Type)
+TYPE(Auto, DeducedType)
+TYPE(DeducedTemplateSpecialization, DeducedType)
DEPENDENT_TYPE(InjectedClassName, Type)
DEPENDENT_TYPE(DependentName, Type)
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h
index 392e544d90c1..fa64fae8824f 100644
--- a/include/clang/AST/TypeOrdering.h
+++ b/include/clang/AST/TypeOrdering.h
@@ -26,7 +26,7 @@
namespace clang {
/// \brief Function object that provides a total ordering on QualType values.
-struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
+struct QualTypeOrdering {
bool operator()(QualType T1, QualType T2) const {
return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
}
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 6a5224febab5..fb029470c830 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -180,6 +180,16 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl>
/// matches "using Y = int", but not "typedef int X"
const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl;
+/// \brief Matches type alias template declarations.
+///
+/// typeAliasTemplateDecl() matches
+/// \code
+/// template <typename T>
+/// using Y = X<T>;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl>
+ typeAliasTemplateDecl;
+
/// \brief Matches AST nodes that were expanded within the main-file.
///
/// Example matches X but not Y
@@ -1118,6 +1128,69 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
ObjCInterfaceDecl> objcInterfaceDecl;
+/// \brief Matches Objective-C protocol declarations.
+///
+/// Example matches FooDelegate
+/// \code
+/// @protocol FooDelegate
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCProtocolDecl> objcProtocolDecl;
+
+/// \brief Matches Objective-C category declarations.
+///
+/// Example matches Foo (Additions)
+/// \code
+/// @interface Foo (Additions)
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCCategoryDecl> objcCategoryDecl;
+
+/// \brief Matches Objective-C method declarations.
+///
+/// Example matches both declaration and definition of -[Foo method]
+/// \code
+/// @interface Foo
+/// - (void)method;
+/// @end
+///
+/// @implementation Foo
+/// - (void)method {}
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCMethodDecl> objcMethodDecl;
+
+/// \brief Matches Objective-C instance variable declarations.
+///
+/// Example matches _enabled
+/// \code
+/// @implementation Foo {
+/// BOOL _enabled;
+/// }
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCIvarDecl> objcIvarDecl;
+
+/// \brief Matches Objective-C property declarations.
+///
+/// Example matches enabled
+/// \code
+/// @interface Foo
+/// @property BOOL enabled;
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCPropertyDecl> objcPropertyDecl;
+
/// \brief Matches expressions that introduce cleanups to be run at the end
/// of the sub-expression's evaluation.
///
@@ -2522,7 +2595,7 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
/// \brief Matches on the receiver of an ObjectiveC Message expression.
///
/// Example
-/// matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *")));
+/// matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *")));
/// matches the [webView ...] message invocation.
/// \code
/// NSString *webViewJavaScript = ...
@@ -5507,7 +5580,7 @@ AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
integerLiteral(equals(0), hasParent(expr(hasType(pointerType())))));
}
-/// \brief Matches declaration of the function the statemenet belongs to
+/// \brief Matches declaration of the function the statement belongs to
///
/// Given:
/// \code
diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h
index 2c80b5137320..c5426dd75ef5 100644
--- a/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -56,7 +56,7 @@ class ArgKind {
/// \param To the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
bool operator<(const ArgKind &Other) const {
@@ -182,7 +182,7 @@ public:
/// \param Kind the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
unsigned *Specificity) const {
if (Value)
@@ -281,7 +281,7 @@ public:
/// \param Kind the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
/// \brief Determines if the contained value can be converted to any kind
@@ -290,7 +290,7 @@ public:
/// \param Kinds the requested destination types.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion. It is the maximum specificity of all the possible
+ /// conversion. It is the maximum specificity of all the possible
/// conversions.
bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h
index b8ae67cbba49..a2a27a8e47c7 100644
--- a/include/clang/Analysis/CallGraph.h
+++ b/include/clang/Analysis/CallGraph.h
@@ -98,7 +98,7 @@ public:
bool VisitFunctionDecl(FunctionDecl *FD) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
- if (includeInGraph(FD)) {
+ if (includeInGraph(FD) && FD->isThisDeclarationADefinition()) {
// Add all blocks declared inside this function to the graph.
addNodesForBlocks(FD);
// If this function has external linkage, anything could call it.
diff --git a/include/clang/Analysis/CloneDetection.h b/include/clang/Analysis/CloneDetection.h
index 51cad7a96d6f..3b8173558408 100644
--- a/include/clang/Analysis/CloneDetection.h
+++ b/include/clang/Analysis/CloneDetection.h
@@ -16,9 +16,7 @@
#define LLVM_CLANG_AST_CLONEDETECTION_H
#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/StringMap.h"
-
+#include "llvm/ADT/SmallVector.h"
#include <vector>
namespace clang {
@@ -29,7 +27,7 @@ class VarDecl;
class ASTContext;
class CompoundStmt;
-/// \brief Identifies a list of statements.
+/// Identifies a list of statements.
///
/// Can either identify a single arbitrary Stmt object, a continuous sequence of
/// child statements inside a CompoundStmt or no statements at all.
@@ -39,8 +37,8 @@ class StmtSequence {
/// Stmt, then S is a pointer to this Stmt.
const Stmt *S;
- /// The related ASTContext for S.
- ASTContext *Context;
+ /// The declaration that contains the statements.
+ const Decl *D;
/// If EndIndex is non-zero, then S is a CompoundStmt and this StmtSequence
/// instance is representing the CompoundStmt children inside the array
@@ -49,7 +47,7 @@ class StmtSequence {
unsigned EndIndex;
public:
- /// \brief Constructs a StmtSequence holding multiple statements.
+ /// Constructs a StmtSequence holding multiple statements.
///
/// The resulting StmtSequence identifies a continuous sequence of statements
/// in the body of the given CompoundStmt. Which statements of the body should
@@ -57,20 +55,20 @@ public:
/// that describe a non-empty sub-array in the body of the given CompoundStmt.
///
/// \param Stmt A CompoundStmt that contains all statements in its body.
- /// \param Context The ASTContext for the given CompoundStmt.
+ /// \param D The Decl containing this Stmt.
/// \param StartIndex The inclusive start index in the children array of
/// \p Stmt
/// \param EndIndex The exclusive end index in the children array of \p Stmt.
- StmtSequence(const CompoundStmt *Stmt, ASTContext &Context,
- unsigned StartIndex, unsigned EndIndex);
+ StmtSequence(const CompoundStmt *Stmt, const Decl *D, unsigned StartIndex,
+ unsigned EndIndex);
- /// \brief Constructs a StmtSequence holding a single statement.
+ /// Constructs a StmtSequence holding a single statement.
///
/// \param Stmt An arbitrary Stmt.
- /// \param Context The ASTContext for the given Stmt.
- StmtSequence(const Stmt *Stmt, ASTContext &Context);
+ /// \param D The Decl containing this Stmt.
+ StmtSequence(const Stmt *Stmt, const Decl *D);
- /// \brief Constructs an empty StmtSequence.
+ /// Constructs an empty StmtSequence.
StmtSequence();
typedef const Stmt *const *iterator;
@@ -110,9 +108,12 @@ public:
bool empty() const { return size() == 0; }
/// Returns the related ASTContext for the stored Stmts.
- ASTContext &getASTContext() const {
- assert(Context);
- return *Context;
+ ASTContext &getASTContext() const;
+
+ /// Returns the declaration that contains the stored Stmts.
+ const Decl *getContainingDecl() const {
+ assert(D);
+ return D;
}
/// Returns true if this objects holds a list of statements.
@@ -150,106 +151,215 @@ public:
bool contains(const StmtSequence &Other) const;
};
-/// \brief Searches for clones in source code.
+/// Searches for similar subtrees in the AST.
///
-/// First, this class needs a translation unit which is passed via
-/// \p analyzeTranslationUnit . It will then generate and store search data
-/// for all statements inside the given translation unit.
-/// Afterwards the generated data can be used to find code clones by calling
-/// \p findClones .
+/// First, this class needs several declarations with statement bodies which
+/// can be passed via analyzeCodeBody. Afterwards all statements can be
+/// searched for clones by calling findClones with a given list of constraints
+/// that should specify the wanted properties of the clones.
+///
+/// The result of findClones can be further constrained with the constrainClones
+/// method.
///
/// This class only searches for clones in exectuable source code
/// (e.g. function bodies). Other clones (e.g. cloned comments or declarations)
/// are not supported.
class CloneDetector {
+
public:
- typedef unsigned DataPiece;
-
- /// Holds the data about a StmtSequence that is needed during the search for
- /// code clones.
- struct CloneSignature {
- /// \brief The hash code of the StmtSequence.
- ///
- /// The initial clone groups that are formed during the search for clones
- /// consist only of Sequences that share the same hash code. This makes this
- /// value the central part of this heuristic that is needed to find clones
- /// in a performant way. For this to work, the type of this variable
- /// always needs to be small and fast to compare.
- ///
- /// Also, StmtSequences that are clones of each others have to share
- /// the same hash code. StmtSequences that are not clones of each other
- /// shouldn't share the same hash code, but if they do, it will only
- /// degrade the performance of the hash search but doesn't influence
- /// the correctness of the result.
- size_t Hash;
-
- /// \brief The complexity of the StmtSequence.
- ///
- /// This value gives an approximation on how many direct or indirect child
- /// statements are contained in the related StmtSequence. In general, the
- /// greater this value, the greater the amount of statements. However, this
- /// is only an approximation and the actual amount of statements can be
- /// higher or lower than this value. Statements that are generated by the
- /// compiler (e.g. macro expansions) for example barely influence the
- /// complexity value.
- ///
- /// The main purpose of this value is to filter clones that are too small
- /// and therefore probably not interesting enough for the user.
- unsigned Complexity;
-
- /// \brief Creates an empty CloneSignature without any data.
- CloneSignature() : Complexity(1) {}
-
- CloneSignature(llvm::hash_code Hash, unsigned Complexity)
- : Hash(Hash), Complexity(Complexity) {}
- };
+ /// A collection of StmtSequences that share an arbitrary property.
+ typedef llvm::SmallVector<StmtSequence, 8> CloneGroup;
- /// Holds group of StmtSequences that are clones of each other and the
- /// complexity value (see CloneSignature::Complexity) that all stored
- /// StmtSequences have in common.
- struct CloneGroup {
- std::vector<StmtSequence> Sequences;
- CloneSignature Signature;
+ /// Generates and stores search data for all statements in the body of
+ /// the given Decl.
+ void analyzeCodeBody(const Decl *D);
- CloneGroup() {}
+ /// Constrains the given list of clone groups with the given constraint.
+ ///
+ /// The constraint is expected to have a method with the signature
+ /// `void constrain(std::vector<CloneDetector::CloneGroup> &Sequences)`
+ /// as this is the interface that the CloneDetector uses for applying the
+ /// constraint. The constraint is supposed to directly modify the passed list
+ /// so that all clones in the list fulfill the specific property this
+ /// constraint ensures.
+ template <typename T>
+ static void constrainClones(std::vector<CloneGroup> &CloneGroups, T C) {
+ C.constrain(CloneGroups);
+ }
- CloneGroup(const StmtSequence &Seq, CloneSignature Signature)
- : Signature(Signature) {
- Sequences.push_back(Seq);
- }
+ /// Constrains the given list of clone groups with the given list of
+ /// constraints.
+ ///
+ /// The constraints are applied in sequence in the order in which they are
+ /// passed to this function.
+ template <typename T1, typename... Ts>
+ static void constrainClones(std::vector<CloneGroup> &CloneGroups, T1 C,
+ Ts... ConstraintList) {
+ constrainClones(CloneGroups, C);
+ constrainClones(CloneGroups, ConstraintList...);
+ }
- /// \brief Returns false if and only if this group should be skipped when
- /// searching for clones.
- bool isValid() const {
- // A clone group with only one member makes no sense, so we skip them.
- return Sequences.size() > 1;
+ /// Searches for clones in all previously passed statements.
+ /// \param Result Output parameter to which all created clone groups are
+ /// added.
+ /// \param ConstraintList The constraints that should be applied to the
+ // result.
+ template <typename... Ts>
+ void findClones(std::vector<CloneGroup> &Result, Ts... ConstraintList) {
+ // The initial assumption is that there is only one clone group and every
+ // statement is a clone of the others. This clone group will then be
+ // split up with the help of the constraints.
+ CloneGroup AllClones;
+ AllClones.reserve(Sequences.size());
+ for (const auto &C : Sequences) {
+ AllClones.push_back(C);
}
- };
- /// \brief Generates and stores search data for all statements in the body of
- /// the given Decl.
- void analyzeCodeBody(const Decl *D);
+ Result.push_back(AllClones);
- /// \brief Stores the CloneSignature to allow future querying.
- void add(const StmtSequence &S, const CloneSignature &Signature);
+ constrainClones(Result, ConstraintList...);
+ }
- /// \brief Searches the provided statements for clones.
+private:
+ CloneGroup Sequences;
+};
+
+/// This class is a utility class that contains utility functions for building
+/// custom constraints.
+class CloneConstraint {
+public:
+ /// Removes all groups by using a filter function.
+ /// \param CloneGroups The list of CloneGroups that is supposed to be
+ /// filtered.
+ /// \param Filter The filter function that should return true for all groups
+ /// that should be removed from the list.
+ static void
+ filterGroups(std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ std::function<bool(const CloneDetector::CloneGroup &)> Filter) {
+ CloneGroups.erase(
+ std::remove_if(CloneGroups.begin(), CloneGroups.end(), Filter),
+ CloneGroups.end());
+ }
+
+ /// Splits the given CloneGroups until the given Compare function returns true
+ /// for all clones in a single group.
+ /// \param CloneGroups A list of CloneGroups that should be modified.
+ /// \param Compare The comparison function that all clones are supposed to
+ /// pass. Should return true if and only if two clones belong
+ /// to the same CloneGroup.
+ static void splitCloneGroups(
+ std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ std::function<bool(const StmtSequence &, const StmtSequence &)> Compare);
+};
+
+/// Searches all children of the given clones for type II clones (i.e. they are
+/// identical in every aspect beside the used variable names).
+class RecursiveCloneTypeIIConstraint {
+
+ /// Generates and saves a hash code for the given Stmt.
+ /// \param S The given Stmt.
+ /// \param D The Decl containing S.
+ /// \param StmtsByHash Output parameter that will contain the hash codes for
+ /// each StmtSequence in the given Stmt.
+ /// \return The hash code of the given Stmt.
///
- /// \param Result Output parameter that is filled with a list of found
- /// clone groups. Each group contains multiple StmtSequences
- /// that were identified to be clones of each other.
- /// \param MinGroupComplexity Only return clones which have at least this
- /// complexity value.
- /// \param CheckPatterns Returns only clone groups in which the referenced
- /// variables follow the same pattern.
- void findClones(std::vector<CloneGroup> &Result, unsigned MinGroupComplexity,
- bool CheckPatterns = true);
-
- /// \brief Describes two clones that reference their variables in a different
- /// pattern which could indicate a programming error.
+ /// If the given Stmt is a CompoundStmt, this method will also generate
+ /// hashes for all possible StmtSequences in the children of this Stmt.
+ size_t saveHash(const Stmt *S, const Decl *D,
+ std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash);
+
+public:
+ void constrain(std::vector<CloneDetector::CloneGroup> &Sequences);
+};
+
+/// Ensures that every clone has at least the given complexity.
+///
+/// Complexity is here defined as the total amount of children of a statement.
+/// This constraint assumes the first statement in the group is representative
+/// for all other statements in the group in terms of complexity.
+class MinComplexityConstraint {
+ unsigned MinComplexity;
+
+public:
+ MinComplexityConstraint(unsigned MinComplexity)
+ : MinComplexity(MinComplexity) {}
+
+ size_t calculateStmtComplexity(const StmtSequence &Seq,
+ const std::string &ParentMacroStack = "");
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(
+ CloneGroups, [this](const CloneDetector::CloneGroup &A) {
+ if (!A.empty())
+ return calculateStmtComplexity(A.front()) < MinComplexity;
+ else
+ return false;
+ });
+ }
+};
+
+/// Ensures that all clone groups contain at least the given amount of clones.
+class MinGroupSizeConstraint {
+ unsigned MinGroupSize;
+
+public:
+ MinGroupSizeConstraint(unsigned MinGroupSize = 2)
+ : MinGroupSize(MinGroupSize) {}
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(CloneGroups,
+ [this](const CloneDetector::CloneGroup &A) {
+ return A.size() < MinGroupSize;
+ });
+ }
+};
+
+/// Ensures that no clone group fully contains another clone group.
+struct OnlyLargestCloneConstraint {
+ void constrain(std::vector<CloneDetector::CloneGroup> &Result);
+};
+
+/// Analyzes the pattern of the referenced variables in a statement.
+class VariablePattern {
+
+ /// Describes an occurence of a variable reference in a statement.
+ struct VariableOccurence {
+ /// The index of the associated VarDecl in the Variables vector.
+ size_t KindID;
+ /// The statement in the code where the variable was referenced.
+ const Stmt *Mention;
+
+ VariableOccurence(size_t KindID, const Stmt *Mention)
+ : KindID(KindID), Mention(Mention) {}
+ };
+
+ /// All occurences of referenced variables in the order of appearance.
+ std::vector<VariableOccurence> Occurences;
+ /// List of referenced variables in the order of appearance.
+ /// Every item in this list is unique.
+ std::vector<const VarDecl *> Variables;
+
+ /// Adds a new variable referenced to this pattern.
+ /// \param VarDecl The declaration of the variable that is referenced.
+ /// \param Mention The SourceRange where this variable is referenced.
+ void addVariableOccurence(const VarDecl *VarDecl, const Stmt *Mention);
+
+ /// Adds each referenced variable from the given statement.
+ void addVariables(const Stmt *S);
+
+public:
+ /// Creates an VariablePattern object with information about the given
+ /// StmtSequence.
+ VariablePattern(const StmtSequence &Sequence) {
+ for (const Stmt *S : Sequence)
+ addVariables(S);
+ }
+
+ /// Describes two clones that reference their variables in a different pattern
+ /// which could indicate a programming error.
struct SuspiciousClonePair {
- /// \brief Utility class holding the relevant information about a single
- /// clone in this pair.
+ /// Utility class holding the relevant information about a single
+ /// clone in this pair.
struct SuspiciousCloneInfo {
/// The variable which referencing in this clone was against the pattern.
const VarDecl *Variable;
@@ -270,17 +380,37 @@ public:
SuspiciousCloneInfo SecondCloneInfo;
};
- /// \brief Searches the provided statements for pairs of clones that don't
- /// follow the same pattern when referencing variables.
- /// \param Result Output parameter that will contain the clone pairs.
- /// \param MinGroupComplexity Only clone pairs in which the clones have at
- /// least this complexity value.
- void findSuspiciousClones(std::vector<SuspiciousClonePair> &Result,
- unsigned MinGroupComplexity);
+ /// Counts the differences between this pattern and the given one.
+ /// \param Other The given VariablePattern to compare with.
+ /// \param FirstMismatch Output parameter that will be filled with information
+ /// about the first difference between the two patterns. This parameter
+ /// can be a nullptr, in which case it will be ignored.
+ /// \return Returns the number of differences between the pattern this object
+ /// is following and the given VariablePattern.
+ ///
+ /// For example, the following statements all have the same pattern and this
+ /// function would return zero:
+ ///
+ /// if (a < b) return a; return b;
+ /// if (x < y) return x; return y;
+ /// if (u2 < u1) return u2; return u1;
+ ///
+ /// But the following statement has a different pattern (note the changed
+ /// variables in the return statements) and would have two differences when
+ /// compared with one of the statements above.
+ ///
+ /// if (a < b) return b; return a;
+ ///
+ /// This function should only be called if the related statements of the given
+ /// pattern and the statements of this objects are clones of each other.
+ unsigned countPatternDifferences(
+ const VariablePattern &Other,
+ VariablePattern::SuspiciousClonePair *FirstMismatch = nullptr);
+};
-private:
- /// Stores all encountered StmtSequences alongside their CloneSignature.
- std::vector<std::pair<CloneSignature, StmtSequence>> Sequences;
+/// Ensures that all clones reference variables in the same pattern.
+struct MatchingVariablePatternConstraint {
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups);
};
} // end namespace clang
diff --git a/include/clang/Basic/AddressSpaces.h b/include/clang/Basic/AddressSpaces.h
index 63df61bedbc6..0ec5aafd64b6 100644
--- a/include/clang/Basic/AddressSpaces.h
+++ b/include/clang/Basic/AddressSpaces.h
@@ -20,24 +20,32 @@ namespace clang {
namespace LangAS {
-/// \brief Defines the set of possible language-specific address spaces.
+/// \brief Defines the address space values used by the address space qualifier
+/// of QualType.
///
-/// This uses a high starting offset so as not to conflict with any address
-/// space used by a target.
enum ID {
- Offset = 0x7FFF00,
-
- opencl_global = Offset,
+ // The default value 0 is the value used in QualType for the the situation
+ // where there is no address space qualifier. For most languages, this also
+ // corresponds to the situation where there is no address space qualifier in
+ // the source code, except for OpenCL, where the address space value 0 in
+ // QualType represents private address space in OpenCL source code.
+ Default = 0,
+
+ // OpenCL specific address spaces.
+ opencl_global,
opencl_local,
opencl_constant,
opencl_generic,
+ // CUDA specific address spaces.
cuda_device,
cuda_constant,
cuda_shared,
- Last,
- Count = Last-Offset
+ // This denotes the count of language-specific address spaces and also
+ // the offset added to the target-specific address spaces, which are usually
+ // specified by address space attributes __attribute__(address_space(n))).
+ Count
};
/// The type of a lookup table which maps from language-specific address spaces
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index fa60d512a6ff..c5d2c7fc618b 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -258,6 +258,7 @@ class TargetArch<list<string> arches> {
list<string> CXXABIs;
}
def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
+def TargetAVR : TargetArch<["avr"]>;
def TargetMips : TargetArch<["mips", "mipsel"]>;
def TargetMSP430 : TargetArch<["msp430"]>;
def TargetX86 : TargetArch<["x86"]>;
@@ -301,6 +302,9 @@ class Attr {
// Set to true if this attribute can be duplicated on a subject when merging
// attributes. By default, attributes are not merged.
bit DuplicatesAllowedWhileMerging = 0;
+ // Set to true if this attribute meaningful when applied to or inherited
+ // in a class template definition.
+ bit MeaningfulToClassTemplateDefinition = 0;
// Lists language options, one of which is required to be true for the
// attribute to be applicable. If empty, no language options are required.
list<LangOpt> LangOpts = [];
@@ -340,7 +344,7 @@ class TargetSpecificAttr<TargetArch target> {
// should contain a shared value between the attributes.
//
// Target-specific attributes which use this feature should ensure that the
- // spellings match exactly betweeen the attributes, and if the arguments or
+ // spellings match exactly between the attributes, and if the arguments or
// subjects differ, should specify HasCustomParsing = 1 and implement their
// own parsing and semantic handling requirements as-needed.
string ParseKind;
@@ -372,6 +376,7 @@ def AbiTag : Attr {
let Args = [VariadicStringArgument<"Tags">];
let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag,
"ExpectedStructClassVariableFunctionOrInlineNamespace">;
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [AbiTagsDocs];
}
@@ -449,6 +454,15 @@ def XRayInstrument : InheritableAttr {
let Documentation = [XRayDocs];
}
+def XRayLogArgs : InheritableAttr {
+ let Spellings = [GNU<"xray_log_args">, CXX11<"clang", "xray_log_args">];
+ let Subjects = SubjectList<
+ [CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod"
+ >;
+ let Args = [UnsignedArgument<"ArgumentCount">];
+ let Documentation = [XRayDocs];
+}
+
def TLSModel : InheritableAttr {
let Spellings = [GCC<"tls_model">];
let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">;
@@ -480,6 +494,19 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
let Documentation = [ARMInterruptDocs];
}
+def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> {
+ let Spellings = [GNU<"interrupt">];
+ let Subjects = SubjectList<[Function]>;
+ let ParseKind = "Interrupt";
+ let Documentation = [AVRInterruptDocs];
+}
+
+def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
+ let Spellings = [GNU<"signal">];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [AVRSignalDocs];
+}
+
def AsmLabel : InheritableAttr {
let Spellings = [Keyword<"asm">, Keyword<"__asm__">];
let Args = [StringArgument<"Label">];
@@ -513,6 +540,17 @@ def Availability : InheritableAttr {
let Documentation = [AvailabilityDocs];
}
+def ExternalSourceSymbol : InheritableAttr {
+ let Spellings = [GNU<"external_source_symbol">,
+ CXX11<"clang", "external_source_symbol">];
+ let Args = [StringArgument<"language", 1>,
+ StringArgument<"definedIn", 1>,
+ BoolArgument<"generatedDeclaration", 1>];
+ let HasCustomParsing = 1;
+// let Subjects = SubjectList<[Named]>;
+ let Documentation = [ExternalSourceSymbolDocs];
+}
+
def Blocks : InheritableAttr {
let Spellings = [GNU<"blocks">];
let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>];
@@ -771,6 +809,7 @@ def Deprecated : InheritableAttr {
// An optional string argument that enables us to provide a
// Fix-It.
StringArgument<"Replacement", 1>];
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [DeprecatedDocs];
}
@@ -847,7 +886,15 @@ def FlagEnum : InheritableAttr {
let Spellings = [GNU<"flag_enum">];
let Subjects = SubjectList<[Enum]>;
let Documentation = [FlagEnumDocs];
- let LangOpts = [COnly];
+}
+
+def EnumExtensibility : InheritableAttr {
+ let Spellings = [GNU<"enum_extensibility">,
+ CXX11<"clang", "enum_extensibility">];
+ let Subjects = SubjectList<[Enum]>;
+ let Args = [EnumArgument<"Extensibility", "Kind",
+ ["closed", "open"], ["Closed", "Open"]>];
+ let Documentation = [EnumExtensibilityDocs];
}
def Flatten : InheritableAttr {
@@ -1115,7 +1162,7 @@ def NoSplitStack : InheritableAttr {
let Documentation = [NoSplitStackDocs];
}
-def NonNull : InheritableAttr {
+def NonNull : InheritableParamAttr {
let Spellings = [GCC<"nonnull">];
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag,
"ExpectedFunctionMethodOrParameter">;
@@ -1178,6 +1225,14 @@ def AssumeAligned : InheritableAttr {
let Documentation = [AssumeAlignedDocs];
}
+def AllocAlign : InheritableAttr {
+ let Spellings = [GCC<"alloc_align">];
+ let Subjects = SubjectList<[HasFunctionProto], WarnDiag,
+ "ExpectedFunctionWithProtoType">;
+ let Args = [IntArgument<"ParamIndex">];
+ let Documentation = [AllocAlignDocs];
+}
+
def NoReturn : InheritableAttr {
let Spellings = [GCC<"noreturn">, Declspec<"noreturn">];
// FIXME: Does GCC allow this on the function instead?
@@ -1498,6 +1553,12 @@ def SwiftIndirectResult : ParameterABIAttr {
let Documentation = [SwiftIndirectResultDocs];
}
+def Suppress : StmtAttr {
+ let Spellings = [CXX11<"gsl", "suppress">];
+ let Args = [VariadicStringArgument<"DiagnosticIdentifiers">];
+ let Documentation = [SuppressDocs];
+}
+
def SysVABI : InheritableAttr {
let Spellings = [GCC<"sysv_abi">];
// let Subjects = [Function, ObjCMethod];
@@ -1681,6 +1742,7 @@ def Visibility : InheritableAttr {
let Args = [EnumArgument<"Visibility", "VisibilityType",
["default", "hidden", "internal", "protected"],
["Default", "Hidden", "Hidden", "Protected"]>];
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [Undocumented];
}
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index 8f6a7ea601b3..71cfe36a8fa4 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -244,6 +244,36 @@ An example of how to use ``alloc_size``
}];
}
+def AllocAlignDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Use ``__attribute__((alloc_align(<alignment>))`` on a function
+declaration to specify that the return value of the function (which must be a
+pointer type) is at least as aligned as the value of the indicated parameter. The
+parameter is given by its index in the list of formal parameters; the first
+parameter has index 1 unless the function is a C++ non-static member function,
+in which case the first parameter has index 2 to account for the implicit ``this``
+parameter.
+
+.. code-block:: c++
+
+ // The returned pointer has the alignment specified by the first parameter.
+ void *a(size_t align) __attribute__((alloc_align(1)));
+
+ // The returned pointer has the alignment specified by the second parameter.
+ void *b(void *v, size_t align) __attribute__((alloc_align(2)));
+
+ // The returned pointer has the alignment specified by the second visible
+ // parameter, however it must be adjusted for the implicit 'this' parameter.
+ void *Foo::b(void *v, size_t align) __attribute__((alloc_align(3)));
+
+Note that this attribute merely informs the compiler that a function always
+returns a sufficiently aligned pointer. It does not cause the compiler to
+emit code to enforce that alignment. The behavior is undefined if the returned
+poitner is not sufficiently aligned.
+ }];
+}
+
def EnableIfDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -960,6 +990,63 @@ When one method overrides another, the overriding method can be more widely avai
}];
}
+def ExternalSourceSymbolDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``external_source_symbol`` attribute specifies that a declaration originates
+from an external source and describes the nature of that source.
+
+The fact that Clang is capable of recognizing declarations that were defined
+externally can be used to provide better tooling support for mixed-language
+projects or projects that rely on auto-generated code. For instance, an IDE that
+uses Clang and that supports mixed-language projects can use this attribute to
+provide a correct 'jump-to-definition' feature. For a concrete example,
+consider a protocol that's defined in a Swift file:
+
+.. code-block:: swift
+
+ @objc public protocol SwiftProtocol {
+ func method()
+ }
+
+This protocol can be used from Objective-C code by including a header file that
+was generated by the Swift compiler. The declarations in that header can use
+the ``external_source_symbol`` attribute to make Clang aware of the fact
+that ``SwiftProtocol`` actually originates from a Swift module:
+
+.. code-block:: objc
+
+ __attribute__((external_source_symbol(language="Swift",defined_in="module")))
+ @protocol SwiftProtocol
+ @required
+ - (void) method;
+ @end
+
+Consequently, when 'jump-to-definition' is performed at a location that
+references ``SwiftProtocol``, the IDE can jump to the original definition in
+the Swift source file rather than jumping to the Objective-C declaration in the
+auto-generated header file.
+
+The ``external_source_symbol`` attribute is a comma-separated list that includes
+clauses that describe the origin and the nature of the particular declaration.
+Those clauses can be:
+
+language=\ *string-literal*
+ The name of the source language in which this declaration was defined.
+
+defined_in=\ *string-literal*
+ The name of the source container in which the declaration was defined. The
+ exact definition of source container is language-specific, e.g. Swift's
+ source containers are modules, so ``defined_in`` should specify the Swift
+ module name.
+
+generated_declaration
+ This declaration was automatically generated by some tool.
+
+The clauses can be specified in any order. The clauses that are listed above are
+all optional, but the attribute has to have at least one clause.
+ }];
+}
def RequireConstantInitDocs : Documentation {
let Category = DocCatVariable;
@@ -1182,6 +1269,33 @@ The semantics are as follows:
}];
}
+def AVRInterruptDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((interrupt))`` attribute on
+AVR targets. This attribute may be attached to a function definition and instructs
+the backend to generate appropriate function entry/exit code so that it can be used
+directly as an interrupt service routine.
+
+On the AVR, the hardware globally disables interrupts when an interrupt is executed.
+The first instruction of an interrupt handler declared with this attribute is a SEI
+instruction to re-enable interrupts. See also the signal attribute that
+does not insert a SEI instruction.
+ }];
+}
+
+def AVRSignalDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((signal))`` attribute on
+AVR targets. This attribute may be attached to a function definition and instructs
+the backend to generate appropriate function entry/exit code so that it can be used
+directly as an interrupt service routine.
+
+Interrupt handler functions defined with the signal attribute do not re-enable interrupts.
+}];
+}
+
def TargetDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -1879,6 +1993,55 @@ manipulating bits of the enumerator when issuing warnings.
}];
}
+def EnumExtensibilityDocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+Attribute ``enum_extensibility`` is used to distinguish between enum definitions
+that are extensible and those that are not. The attribute can take either
+``closed`` or ``open`` as an argument. ``closed`` indicates a variable of the
+enum type takes a value that corresponds to one of the enumerators listed in the
+enum definition or, when the enum is annotated with ``flag_enum``, a value that
+can be constructed using values corresponding to the enumerators. ``open``
+indicates a variable of the enum type can take any values allowed by the
+standard and instructs clang to be more lenient when issuing warnings.
+
+.. code-block:: c
+
+ enum __attribute__((enum_extensibility(closed))) ClosedEnum {
+ A0, A1
+ };
+
+ enum __attribute__((enum_extensibility(open))) OpenEnum {
+ B0, B1
+ };
+
+ enum __attribute__((enum_extensibility(closed),flag_enum)) ClosedFlagEnum {
+ C0 = 1 << 0, C1 = 1 << 1
+ };
+
+ enum __attribute__((enum_extensibility(open),flag_enum)) OpenFlagEnum {
+ D0 = 1 << 0, D1 = 1 << 1
+ };
+
+ void foo1() {
+ enum ClosedEnum ce;
+ enum OpenEnum oe;
+ enum ClosedFlagEnum cfe;
+ enum OpenFlagEnum ofe;
+
+ ce = A1; // no warnings
+ ce = 100; // warning issued
+ oe = B1; // no warnings
+ oe = 100; // no warnings
+ cfe = C0 | C1; // no warnings
+ cfe = C0 | C1 | 4; // warning issued
+ ofe = D0 | D1; // no warnings
+ ofe = D0 | D1 | 4; // no warnings
+ }
+
+ }];
+}
+
def EmptyBasesDocs : Documentation {
let Category = DocCatType;
let Content = [{
@@ -2638,6 +2801,32 @@ optimizations like C++'s named return value optimization (NRVO).
}];
}
+def SuppressDocs : Documentation {
+ let Category = DocCatStmt;
+ let Content = [{
+The ``[[gsl::suppress]]`` attribute suppresses specific
+clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable
+way. The attribute can be attached to declarations, statements, and at
+namespace scope.
+
+.. code-block:: c++
+
+ [[gsl::suppress("Rh-public")]]
+ void f_() {
+ int *p;
+ [[gsl::suppress("type")]] {
+ p = reinterpret_cast<int*>(7);
+ }
+ }
+ namespace N {
+ [[clang::suppress("type", "bounds")]];
+ ...
+ }
+
+.. _`C++ Core Guidelines`: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement
+ }];
+}
+
def AbiTagsDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -2777,13 +2966,15 @@ See the RenderScript_ documentation for more information.
def XRayDocs : Documentation {
let Category = DocCatFunction;
- let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument)";
+ let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument), xray_log_args (clang::xray_log_args)";
let Content = [{
``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching.
Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points.
If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise.
+
+``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported.
}];
}
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 326a8fa66360..816ea156f979 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -756,11 +756,11 @@ LANGBUILTIN(_InterlockedOr, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedXor8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedXor16, "ssD*s", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedXor, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandset, "UcLiD*Li", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt64, "ULLiULLi", "nc", ALL_MS_LANGUAGES)
-LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl8, "UcUcUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl16, "UsUsUc", "n", ALL_MS_LANGUAGES)
@@ -773,6 +773,7 @@ LANGBUILTIN(_rotr, "UiUii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_lrotr, "ULiULii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
+LANGBUILTIN(__fastfail, "vUi", "nr", ALL_MS_LANGUAGES)
// Microsoft library builtins.
LIBBUILTIN(_setjmpex, "iJ", "fj", "setjmpex.h", ALL_MS_LANGUAGES)
@@ -1086,9 +1087,11 @@ LIBBUILTIN(ilogb, "id", "fne", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ilogbf, "if", "fne", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ilogbl, "iLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(lgamma, "dd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(lgammaf, "ff", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(lgammal, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+// POSIX math.h declares a global, signgam, that lgamma writes to, so these
+// shouldn't have "e" or "c" attributes
+LIBBUILTIN(lgamma, "dd", "fn", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lgammaf, "ff", "fn", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lgammal, "LdLd", "fn", "math.h", ALL_LANGUAGES)
LIBBUILTIN(llrint, "LLid", "fne", "math.h", ALL_LANGUAGES)
LIBBUILTIN(llrintf, "LLif", "fne", "math.h", ALL_LANGUAGES)
@@ -1362,7 +1365,7 @@ BUILTIN(__builtin_coro_free, "v*v*", "n")
BUILTIN(__builtin_coro_id, "v*Iiv*v*v*", "n")
BUILTIN(__builtin_coro_alloc, "b", "n")
BUILTIN(__builtin_coro_begin, "v*v*", "n")
-BUILTIN(__builtin_coro_end, "vv*Ib", "n")
+BUILTIN(__builtin_coro_end, "bv*Ib", "n")
BUILTIN(__builtin_coro_suspend, "cIb", "n")
BUILTIN(__builtin_coro_param, "bv*v*", "n")
// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
diff --git a/include/clang/Basic/BuiltinsAMDGPU.def b/include/clang/Basic/BuiltinsAMDGPU.def
index f0f63fa73a79..a8ab657c379e 100644
--- a/include/clang/Basic/BuiltinsAMDGPU.def
+++ b/include/clang/Basic/BuiltinsAMDGPU.def
@@ -35,8 +35,14 @@ BUILTIN(__builtin_amdgcn_workitem_id_z, "Ui", "nc")
//===----------------------------------------------------------------------===//
// Instruction builtins.
//===----------------------------------------------------------------------===//
+BUILTIN(__builtin_amdgcn_s_getreg, "UiIi", "n")
+BUILTIN(__builtin_amdgcn_s_waitcnt, "vIi", "n")
+BUILTIN(__builtin_amdgcn_s_sendmsg, "vIiUi", "n")
+BUILTIN(__builtin_amdgcn_s_sendmsghalt, "vIiUi", "n")
BUILTIN(__builtin_amdgcn_s_barrier, "v", "n")
BUILTIN(__builtin_amdgcn_wave_barrier, "v", "n")
+BUILTIN(__builtin_amdgcn_s_dcache_inv, "v", "n")
+BUILTIN(__builtin_amdgcn_buffer_wbinvl1, "v", "n")
BUILTIN(__builtin_amdgcn_div_scale, "dddbb*", "n")
BUILTIN(__builtin_amdgcn_div_scalef, "fffbb*", "n")
BUILTIN(__builtin_amdgcn_div_fmas, "ddddb", "nc")
@@ -80,6 +86,11 @@ BUILTIN(__builtin_amdgcn_sicmpl, "LUiLiLiIi", "nc")
BUILTIN(__builtin_amdgcn_fcmp, "LUiddIi", "nc")
BUILTIN(__builtin_amdgcn_fcmpf, "LUiffIi", "nc")
BUILTIN(__builtin_amdgcn_ds_swizzle, "iiIi", "nc")
+BUILTIN(__builtin_amdgcn_ds_permute, "iii", "nc")
+BUILTIN(__builtin_amdgcn_ds_bpermute, "iii", "nc")
+BUILTIN(__builtin_amdgcn_readfirstlane, "ii", "nc")
+BUILTIN(__builtin_amdgcn_readlane, "iii", "nc")
+BUILTIN(__builtin_amdgcn_fmed3f, "ffff", "nc")
//===----------------------------------------------------------------------===//
// VI+ only builtins.
@@ -96,6 +107,13 @@ TARGET_BUILTIN(__builtin_amdgcn_frexp_exph, "sh", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_fracth, "hh", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_classh, "bhi", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_memrealtime, "LUi", "n", "s-memrealtime")
+TARGET_BUILTIN(__builtin_amdgcn_mov_dpp, "iiIiIiIiIb", "nc", "dpp")
+
+//===----------------------------------------------------------------------===//
+// GFX9+ only builtins.
+//===----------------------------------------------------------------------===//
+
+TARGET_BUILTIN(__builtin_amdgcn_fmed3h, "hhhh", "nc", "gfx9-insts")
//===----------------------------------------------------------------------===//
// Special builtins.
diff --git a/include/clang/Basic/BuiltinsNVPTX.def b/include/clang/Basic/BuiltinsNVPTX.def
index b6329fbd4251..afea6cb0f1b2 100644
--- a/include/clang/Basic/BuiltinsNVPTX.def
+++ b/include/clang/Basic/BuiltinsNVPTX.def
@@ -64,24 +64,10 @@ BUILTIN(__nvvm_read_ptx_sreg_pm3, "i", "n")
// MISC
-BUILTIN(__nvvm_clz_i, "ii", "")
-BUILTIN(__nvvm_clz_ll, "iLLi", "")
-BUILTIN(__nvvm_popc_i, "ii", "")
-BUILTIN(__nvvm_popc_ll, "iLLi", "")
BUILTIN(__nvvm_prmt, "UiUiUiUi", "")
// Min Max
-BUILTIN(__nvvm_min_i, "iii", "")
-BUILTIN(__nvvm_min_ui, "UiUiUi", "")
-BUILTIN(__nvvm_min_ll, "LLiLLiLLi", "")
-BUILTIN(__nvvm_min_ull, "ULLiULLiULLi", "")
-
-BUILTIN(__nvvm_max_i, "iii", "")
-BUILTIN(__nvvm_max_ui, "UiUiUi", "")
-BUILTIN(__nvvm_max_ll, "LLiLLiLLi", "")
-BUILTIN(__nvvm_max_ull, "ULLiULLiULLi", "")
-
BUILTIN(__nvvm_fmax_ftz_f, "fff", "")
BUILTIN(__nvvm_fmax_f, "fff", "")
BUILTIN(__nvvm_fmin_ftz_f, "fff", "")
@@ -133,11 +119,6 @@ BUILTIN(__nvvm_div_rz_d, "ddd", "")
BUILTIN(__nvvm_div_rm_d, "ddd", "")
BUILTIN(__nvvm_div_rp_d, "ddd", "")
-// Brev
-
-BUILTIN(__nvvm_brev32, "UiUi", "")
-BUILTIN(__nvvm_brev64, "ULLiULLi", "")
-
// Sad
BUILTIN(__nvvm_sad_i, "iiii", "")
@@ -155,9 +136,6 @@ BUILTIN(__nvvm_ceil_d, "dd", "")
// Abs
-BUILTIN(__nvvm_abs_i, "ii", "")
-BUILTIN(__nvvm_abs_ll, "LLiLLi", "")
-
BUILTIN(__nvvm_fabs_ftz_f, "ff", "")
BUILTIN(__nvvm_fabs_f, "ff", "")
BUILTIN(__nvvm_fabs_d, "dd", "")
@@ -385,8 +363,6 @@ BUILTIN(__nvvm_ull2d_rp, "dULLi", "")
BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "")
BUILTIN(__nvvm_f2h_rn, "Usf", "")
-BUILTIN(__nvvm_h2f, "fUs", "")
-
// Bitcast
BUILTIN(__nvvm_bitcast_f2i, "if", "")
diff --git a/include/clang/Basic/BuiltinsWebAssembly.def b/include/clang/Basic/BuiltinsWebAssembly.def
index 97b59a1fd86c..de56908be83c 100644
--- a/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/include/clang/Basic/BuiltinsWebAssembly.def
@@ -16,9 +16,9 @@
// The format of this database matches clang/Basic/Builtins.def.
-// Note that current_memory is not "c" (readnone) because it must be sequenced with
-// respect to grow_memory calls.
+// Note that current_memory is not "c" (readnone) because it must be sequenced
+// with respect to grow_memory calls.
BUILTIN(__builtin_wasm_current_memory, "z", "n")
-BUILTIN(__builtin_wasm_grow_memory, "vz", "n")
+BUILTIN(__builtin_wasm_grow_memory, "zz", "n")
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index e53992bbf50e..c8a3c2f4d3ab 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -391,7 +391,6 @@ TARGET_BUILTIN(__builtin_ia32_roundsd, "V2dV2dV2dIi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_roundpd, "V2dV2dIi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fIc", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_dppd, "V2dV2dV2dIc", "", "sse4.1")
-TARGET_BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLiC*", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "", "sse4.1")
@@ -576,7 +575,6 @@ TARGET_BUILTIN(__builtin_ia32_psrldi256, "V8iV8ii", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_psrld256, "V8iV8iV4i", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_psrlqi256, "V4LLiV4LLii", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_psrlq256, "V4LLiV4LLiV2LLi", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLiC*", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8i", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "", "avx2")
@@ -832,8 +830,6 @@ TARGET_BUILTIN(__builtin_ia32_vphaddudq, "V2LLiV4i", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vphsubbw, "V8sV16c", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vphsubwd, "V4iV8s", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vphsubdq, "V2LLiV4i", "", "xop")
-TARGET_BUILTIN(__builtin_ia32_vpcmov, "V2LLiV2LLiV2LLiV2LLi", "", "xop")
-TARGET_BUILTIN(__builtin_ia32_vpcmov_256, "V4LLiV4LLiV4LLiV4LLi", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vpperm, "V16cV16cV16cV16c", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vprotb, "V16cV16cV16c", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vprotw, "V8sV8sV8s", "", "xop")
@@ -997,22 +993,22 @@ TARGET_BUILTIN(__builtin_ia32_vpermt2varq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "",
TARGET_BUILTIN(__builtin_ia32_vpermt2varps512_mask, "V16fV16iV16fV16fUs", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_vpermt2varpd512_mask, "V8dV8LLiV8dV8dUc", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_gather3div2df, "V2dV2ddC*V2LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div2di, "V2LLiV2LLiLLiC*V2LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div4df, "V4dV4ddC*V4LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div4di, "V4LLiV4LLiLLiC*V4LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div4sf, "V4fV4ffC*V2LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div4si, "V4iV4iiC*V2LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div8sf, "V4fV4ffC*V4LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div8si, "V4iV4iiC*V4LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv2df, "V2dV2ddC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv2di, "V2LLiV2LLiLLiC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv4df, "V4dV4ddC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv4di, "V4LLiV4LLiLLiC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv4sf, "V4fV4ffC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv4si, "V4iV4iiC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv8sf, "V8fV8ffC*V8iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv8si, "V8iV8iiC*V8iUci","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div2df, "V2dV2ddC*V2LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div2di, "V2LLiV2LLiLLiC*V2LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div4df, "V4dV4ddC*V4LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div4di, "V4LLiV4LLiLLiC*V4LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div4sf, "V4fV4ffC*V2LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div4si, "V4iV4iiC*V2LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div8sf, "V4fV4ffC*V4LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div8si, "V4iV4iiC*V4LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv2df, "V2dV2ddC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv2di, "V2LLiV2LLiLLiC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv4df, "V4dV4ddC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv4di, "V4LLiV4LLiLLiC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv4sf, "V4fV4ffC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv4si, "V4iV4iiC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv8sf, "V8fV8ffC*V8iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv8si, "V8iV8iiC*V8iUcIi","","avx512vl")
TARGET_BUILTIN(__builtin_ia32_gathersiv8df, "V8dV8ddC*V8iUcIi", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_gathersiv16sf, "V16fV16ffC*V16fUsIi", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_gatherdiv8df, "V8dV8ddC*V8LLiUcIi", "", "avx512f")
@@ -1068,10 +1064,10 @@ TARGET_BUILTIN(__builtin_ia32_ucmpw512_mask, "UiV32sV32sIiUi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_pabsb512_mask, "V64cV64cV64cULLi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_pabsw512_mask, "V32sV32sV32sUi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_packssdw512_mask, "V32sV16iV16iV32sUi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_packsswb512_mask, "V64cV32sV32sV64cULLi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_packusdw512_mask, "V32sV16iV16iV32sUi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_packuswb512_mask, "V64cV32sV32sV64cULLi", "", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_packssdw512, "V32sV16iV16i", "", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_packsswb512, "V64cV32sV32s", "", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_packusdw512, "V32sV16iV16i", "", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_packuswb512, "V64cV32sV32s", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_paddsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_paddsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_paddusb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw")
@@ -1590,27 +1586,15 @@ TARGET_BUILTIN(__builtin_ia32_cvtq2mask128, "UcV2LLi","","avx512dq,avx512vl")
TARGET_BUILTIN(__builtin_ia32_cvtq2mask256, "UcV4LLi","","avx512dq,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastmb512, "V8LLiUc","","avx512cd")
TARGET_BUILTIN(__builtin_ia32_broadcastmw512, "V16iUs","","avx512cd")
-TARGET_BUILTIN(__builtin_ia32_broadcastf32x4_512, "V16fV4fV16fUs","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_broadcastf64x4_512, "V8dV4dV8dUc","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_broadcasti32x4_512, "V16iV4iV16iUs","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_broadcasti64x4_512, "V8LLiV4LLiV8LLiUc","","avx512f")
TARGET_BUILTIN(__builtin_ia32_broadcastmb128, "V2LLiUc","","avx512cd,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastmb256, "V4LLiUc","","avx512cd,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastmw128, "V4iUs","","avx512cd,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastmw256, "V8iUs","","avx512cd,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_512_mask, "V16fV4fV16fUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcastf32x8_512_mask, "V16fV8fV16fUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcastf64x2_512_mask, "V8dV2dV8dUc","","avx512dq")
TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_512_mask, "V16iV4iV16iUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcasti32x8_512_mask, "V16iV8iV16iUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcasti64x2_512_mask, "V8LLiV2LLiV8LLiUc","","avx512dq")
TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_256_mask, "V8fV4fV8fUc","","avx512dq,avx512vl")
-TARGET_BUILTIN(__builtin_ia32_broadcastf64x2_256_mask, "V4dV2dV4dUc","","avx512dq,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_128_mask, "V4iV4iV4iUc","","avx512dq,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_256_mask, "V8iV4iV8iUc","","avx512dq,avx512vl")
-TARGET_BUILTIN(__builtin_ia32_broadcasti64x2_256_mask, "V4LLiV2LLiV4LLiUc","","avx512dq,avx512vl")
-TARGET_BUILTIN(__builtin_ia32_broadcastf32x4_256_mask, "V8fV4fV8fUc","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_broadcasti32x4_256_mask, "V8iV4iV8iUc","","avx512vl")
TARGET_BUILTIN(__builtin_ia32_pbroadcastw512_gpr_mask, "V32shV32sUi","","avx512bw")
TARGET_BUILTIN(__builtin_ia32_pbroadcastw256_gpr_mask, "V16shV16sUs","","avx512bw,avx512vl")
TARGET_BUILTIN(__builtin_ia32_pbroadcastw128_gpr_mask, "V8ssV8sUc","","avx512bw,avx512vl")
@@ -1761,7 +1745,6 @@ TARGET_BUILTIN(__builtin_ia32_kortestzhi, "iUsUs","","avx512f")
TARGET_BUILTIN(__builtin_ia32_kunpckhi, "UsUsUs","","avx512f")
TARGET_BUILTIN(__builtin_ia32_kxnorhi, "UsUsUs","","avx512f")
TARGET_BUILTIN(__builtin_ia32_kxorhi, "UsUsUs","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_movntdqa512, "V8LLiV8LLi*","","avx512f")
TARGET_BUILTIN(__builtin_ia32_palignr512_mask, "V64cV64cV64cIiV64cULLi","","avx512bw")
TARGET_BUILTIN(__builtin_ia32_dbpsadbw128_mask, "V8sV16cV16cIiV8sUc","","avx512bw,avx512vl")
TARGET_BUILTIN(__builtin_ia32_dbpsadbw256_mask, "V16sV32cV32cIiV16sUs","","avx512bw,avx512vl")
@@ -1826,6 +1809,9 @@ TARGET_BUILTIN(__builtin_ia32_selectpd_512, "V8dUcV8dV8d", "", "")
TARGET_BUILTIN(__builtin_ia32_monitorx, "vv*UiUi", "", "mwaitx")
TARGET_BUILTIN(__builtin_ia32_mwaitx, "vUiUiUi", "", "mwaitx")
+// CLZERO
+TARGET_BUILTIN(__builtin_ia32_clzero, "vv*", "", "clzero")
+
// MSVC
TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -1840,6 +1826,18 @@ TARGET_HEADER_BUILTIN(__emulu, "ULLiUiUi", "nh", "intrin.h", ALL_MS_LANGUAGES, "
TARGET_HEADER_BUILTIN(_AddressOfReturnAddress, "v*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__stosb, "vUc*Ucz", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__int2c, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__ud2, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "")
+
+TARGET_HEADER_BUILTIN(__readfsbyte, "UcULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsword, "UsULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsdword, "ULiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsqword, "ULLiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+
+TARGET_HEADER_BUILTIN(__readgsbyte, "UcULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsword, "UsULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsdword, "ULiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsqword, "ULLiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
#undef BUILTIN
#undef TARGET_BUILTIN
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index 7b581d3eec0f..3298a80e5134 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -45,6 +45,7 @@ def Named : Decl<1>;
def ObjCAtDefsField : DDecl<Field>;
def MSProperty : DDecl<Declarator>;
def Function : DDecl<Declarator>, DeclContext;
+ def CXXDeductionGuide : DDecl<Function>;
def CXXMethod : DDecl<Function>;
def CXXConstructor : DDecl<CXXMethod>;
def CXXDestructor : DDecl<CXXMethod>;
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index b83ef4d44b24..a8e11bcb8927 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -29,6 +29,7 @@
#include <cassert>
#include <cstdint>
#include <list>
+#include <map>
#include <memory>
#include <string>
#include <type_traits>
@@ -222,6 +223,9 @@ private:
void setMapping(diag::kind Diag, DiagnosticMapping Info) {
DiagMap[Diag] = Info;
}
+ DiagnosticMapping lookupMapping(diag::kind Diag) const {
+ return DiagMap.lookup(Diag);
+ }
DiagnosticMapping &getOrAddMapping(diag::kind Diag);
@@ -232,59 +236,97 @@ private:
/// \brief Keeps and automatically disposes all DiagStates that we create.
std::list<DiagState> DiagStates;
- /// \brief Represents a point in source where the diagnostic state was
- /// modified because of a pragma.
- ///
- /// 'Loc' can be null if the point represents the diagnostic state
- /// modifications done through the command-line.
- struct DiagStatePoint {
- DiagState *State;
- FullSourceLoc Loc;
- DiagStatePoint(DiagState *State, FullSourceLoc Loc)
- : State(State), Loc(Loc) { }
-
- bool operator<(const DiagStatePoint &RHS) const {
- // If Loc is invalid it means it came from <command-line>, in which case
- // we regard it as coming before any valid source location.
- if (RHS.Loc.isInvalid())
- return false;
- if (Loc.isInvalid())
- return true;
- return Loc.isBeforeInTranslationUnitThan(RHS.Loc);
+ /// A mapping from files to the diagnostic states for those files. Lazily
+ /// built on demand for files in which the diagnostic state has not changed.
+ class DiagStateMap {
+ public:
+ /// Add an initial diagnostic state.
+ void appendFirst(DiagState *State);
+ /// Add a new latest state point.
+ void append(SourceManager &SrcMgr, SourceLocation Loc, DiagState *State);
+ /// Look up the diagnostic state at a given source location.
+ DiagState *lookup(SourceManager &SrcMgr, SourceLocation Loc) const;
+ /// Determine whether this map is empty.
+ bool empty() const { return Files.empty(); }
+ /// Clear out this map.
+ void clear() {
+ Files.clear();
+ FirstDiagState = CurDiagState = nullptr;
+ CurDiagStateLoc = SourceLocation();
}
+
+ /// Grab the most-recently-added state point.
+ DiagState *getCurDiagState() const { return CurDiagState; }
+ /// Get the location at which a diagnostic state was last added.
+ SourceLocation getCurDiagStateLoc() const { return CurDiagStateLoc; }
+
+ private:
+ /// \brief Represents a point in source where the diagnostic state was
+ /// modified because of a pragma.
+ ///
+ /// 'Loc' can be null if the point represents the diagnostic state
+ /// modifications done through the command-line.
+ struct DiagStatePoint {
+ DiagState *State;
+ unsigned Offset;
+ DiagStatePoint(DiagState *State, unsigned Offset)
+ : State(State), Offset(Offset) { }
+ };
+
+ /// Description of the diagnostic states and state transitions for a
+ /// particular FileID.
+ struct File {
+ /// The diagnostic state for the parent file. This is strictly redundant,
+ /// as looking up the DecomposedIncludedLoc for the FileID in the Files
+ /// map would give us this, but we cache it here for performance.
+ File *Parent = nullptr;
+ /// The offset of this file within its parent.
+ unsigned ParentOffset = 0;
+ /// Whether this file has any local (not imported from an AST file)
+ /// diagnostic state transitions.
+ bool HasLocalTransitions = false;
+ /// The points within the file where the state changes. There will always
+ /// be at least one of these (the state on entry to the file).
+ llvm::SmallVector<DiagStatePoint, 4> StateTransitions;
+
+ DiagState *lookup(unsigned Offset) const;
+ };
+
+ /// The diagnostic states for each file.
+ mutable std::map<FileID, File> Files;
+
+ /// The initial diagnostic state.
+ DiagState *FirstDiagState;
+ /// The current diagnostic state.
+ DiagState *CurDiagState;
+ /// The location at which the current diagnostic state was established.
+ SourceLocation CurDiagStateLoc;
+
+ /// Get the diagnostic state information for a file.
+ File *getFile(SourceManager &SrcMgr, FileID ID) const;
+
+ friend class ASTReader;
+ friend class ASTWriter;
};
- /// \brief A sorted vector of all DiagStatePoints representing changes in
- /// diagnostic state due to diagnostic pragmas.
- ///
- /// The vector is always sorted according to the SourceLocation of the
- /// DiagStatePoint.
- typedef std::vector<DiagStatePoint> DiagStatePointsTy;
- mutable DiagStatePointsTy DiagStatePoints;
+ DiagStateMap DiagStatesByLoc;
/// \brief Keeps the DiagState that was active during each diagnostic 'push'
/// so we can get back at it when we 'pop'.
std::vector<DiagState *> DiagStateOnPushStack;
DiagState *GetCurDiagState() const {
- assert(!DiagStatePoints.empty());
- return DiagStatePoints.back().State;
+ return DiagStatesByLoc.getCurDiagState();
}
- void PushDiagStatePoint(DiagState *State, SourceLocation L) {
- FullSourceLoc Loc(L, getSourceManager());
- // Make sure that DiagStatePoints is always sorted according to Loc.
- assert(Loc.isValid() && "Adding invalid loc point");
- assert(!DiagStatePoints.empty() &&
- (DiagStatePoints.back().Loc.isInvalid() ||
- DiagStatePoints.back().Loc.isBeforeInTranslationUnitThan(Loc)) &&
- "Previous point loc comes after or is the same as new one");
- DiagStatePoints.push_back(DiagStatePoint(State, Loc));
- }
+ void PushDiagStatePoint(DiagState *State, SourceLocation L);
/// \brief Finds the DiagStatePoint that contains the diagnostic state of
/// the given source location.
- DiagStatePointsTy::iterator GetDiagStatePointForLoc(SourceLocation Loc) const;
+ DiagState *GetDiagStateForLoc(SourceLocation Loc) const {
+ return SourceMgr ? DiagStatesByLoc.lookup(*SourceMgr, Loc)
+ : DiagStatesByLoc.getCurDiagState();
+ }
/// \brief Sticky flag set to \c true when an error is emitted.
bool ErrorOccurred;
@@ -390,7 +432,11 @@ public:
assert(SourceMgr && "SourceManager not set!");
return *SourceMgr;
}
- void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; }
+ void setSourceManager(SourceManager *SrcMgr) {
+ assert(DiagStatesByLoc.empty() &&
+ "Leftover diag state from a different SourceManager.");
+ SourceMgr = SrcMgr;
+ }
//===--------------------------------------------------------------------===//
// DiagnosticsEngine characterization methods, used by a client to customize
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 03ed8aa74597..652d06278557 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -44,7 +44,8 @@ def note_constexpr_non_global : Note<
def note_constexpr_uninitialized : Note<
"%select{|sub}0object of type %1 is not initialized">;
def note_constexpr_array_index : Note<"cannot refer to element %0 of "
- "%select{array of %2 elements|non-array object}1 in a constant expression">;
+ "%select{array of %2 element%plural{1:|:s}2|non-array object}1 "
+ "in a constant expression">;
def note_constexpr_float_arithmetic : Note<
"floating point arithmetic produces %select{an infinity|a NaN}0">;
def note_constexpr_pointer_subtraction_not_same_array : Note<
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index af0612a829e1..98fd3c4d57ac 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -45,7 +45,9 @@ def err_expected_colon_after_setter_name : Error<
"must end with ':'">;
def err_expected_string_literal : Error<"expected string literal "
"%select{in %1|for diagnostic message in static_assert|"
- "for optional message in 'availability' attribute}0">;
+ "for optional message in 'availability' attribute|"
+ "for %select{language|source container}1 name in "
+ "'external_source_symbol' attribute}0">;
def err_invalid_string_udl : Error<
"string literal with user-defined suffix cannot be used here">;
def err_invalid_character_udl : Error<
@@ -88,10 +90,10 @@ def err_module_unavailable : Error<
"module '%0' %select{is incompatible with|requires}1 feature '%2'">;
def err_module_header_missing : Error<
"%select{|umbrella }0header '%1' not found">;
-def err_module_lock_failure : Error<
- "could not acquire lock file for module '%0': %1">, DefaultFatal;
-def err_module_lock_timeout : Error<
- "timed out waiting to acquire lock file for module '%0'">, DefaultFatal;
+def remark_module_lock_failure : Remark<
+ "could not acquire lock file for module '%0': %1">, InGroup<ModuleBuild>;
+def remark_module_lock_timeout : Remark<
+ "timed out waiting to acquire lock file for module '%0'">, InGroup<ModuleBuild>;
def err_module_cycle : Error<"cyclic dependency in module '%0': %1">,
DefaultFatal;
def err_module_prebuilt : Error<
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 2fcd3a5a2fba..3980805ef9bc 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -85,6 +85,8 @@ def err_drv_clang_unsupported : Error<
"the clang compiler does not support '%0'">;
def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error<
"the clang compiler does not support '%0' for C++ on Darwin/i386">;
+def err_drv_clang_unsupported_opt_faltivec : Error<
+ "the clang compiler does not support '%0', %1">;
def err_drv_command_failed : Error<
"%0 command failed with exit code %1 (use -v to see invocation)">;
def err_drv_compilationdatabase : Error<
@@ -92,7 +94,7 @@ def err_drv_compilationdatabase : Error<
def err_drv_command_signalled : Error<
"%0 command failed due to signal (use -v to see invocation)">;
def err_drv_force_crash : Error<
- "failing because environment variable '%0' is set">;
+ "failing because %select{environment variable 'FORCE_CLANG_DIAGNOSTICS_CRASH' is set|'-gen-reproducer' is used}0">;
def err_drv_invalid_mfloat_abi : Error<
"invalid float ABI '%0'">;
def err_drv_invalid_libcxx_deployment : Error<
@@ -133,6 +135,7 @@ def err_drv_invalid_gcc_output_type : Error<
"invalid output type '%0' for use with gcc tool">;
def err_drv_cc_print_options_failure : Error<
"unable to open CC_PRINT_OPTIONS file: %0">;
+def err_drv_lto_without_lld : Error<"LTO requires -fuse-ld=lld">;
def err_drv_preamble_format : Error<
"incorrect format for -preamble-bytes=N,END">;
def err_drv_conflicting_deployment_targets : Error<
@@ -230,6 +233,7 @@ def note_drv_t_option_is_global : Note<
"The last /TC or /TP option takes precedence over earlier instances">;
def note_drv_address_sanitizer_debug_runtime : Note<
"AddressSanitizer doesn't support linking with debug runtime libraries yet">;
+def note_drv_use_standard : Note<"use '%0' for '%1' standard">;
def err_analyzer_config_no_value : Error<
"analyzer-config option '%0' has a key but no value">;
@@ -247,6 +251,10 @@ def err_test_module_file_extension_format : Error<
def warn_drv_invoking_fallback : Warning<"falling back to %0">,
InGroup<Fallback>;
+def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">,
+ InGroup<DiagGroup<"slash-u-filename">>;
+def note_use_dashdash : Note<"Use '--' to treat subsequent arguments as filenames">;
+
def err_drv_ropi_rwpi_incompatible_with_pic : Error<
"embedded and GOT-based position independence are incompatible">;
def err_drv_ropi_incompatible_with_cxx : Error<
@@ -277,4 +285,8 @@ def warn_drv_ps4_sdk_dir : Warning<
def err_drv_unsupported_linker : Error<"unsupported value '%0' for -linker option">;
def err_drv_defsym_invalid_format : Error<"defsym must be of the form: sym=value: %0">;
def err_drv_defsym_invalid_symval : Error<"Value is not an integer: %0">;
+def warn_drv_msvc_not_found : Warning<
+ "unable to find a Visual Studio installation; "
+ "try running Clang from a developer command prompt">,
+ InGroup<DiagGroup<"msvc-not-found">>;
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 4173d03de9f0..9f5f9888a819 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -34,7 +34,9 @@ def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">;
def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">;
def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">;
def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">;
+def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">;
def BitFieldWidth : DiagGroup<"bitfield-width">;
+def Coroutine : DiagGroup<"coroutine">;
def ConstantConversion :
DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >;
def LiteralConversion : DiagGroup<"literal-conversion">;
@@ -175,6 +177,8 @@ def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
+def CXX11WarnOverrideDestructor :
+ DiagGroup<"inconsistent-missing-destructor-override">;
def CXX11WarnOverrideMethod : DiagGroup<"inconsistent-missing-override">;
// Original name of this warning in Clang
@@ -355,6 +359,7 @@ def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
def Sentinel : DiagGroup<"sentinel">;
def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
+def ShadowField : DiagGroup<"shadow-field">;
def ShadowFieldInConstructorModified : DiagGroup<"shadow-field-in-constructor-modified">;
def ShadowFieldInConstructor : DiagGroup<"shadow-field-in-constructor",
[ShadowFieldInConstructorModified]>;
@@ -366,7 +371,7 @@ def ShadowUncapturedLocal : DiagGroup<"shadow-uncaptured-local">;
def Shadow : DiagGroup<"shadow", [ShadowFieldInConstructorModified,
ShadowIvar]>;
def ShadowAll : DiagGroup<"shadow-all", [Shadow, ShadowFieldInConstructor,
- ShadowUncapturedLocal]>;
+ ShadowUncapturedLocal, ShadowField]>;
def Shorten64To32 : DiagGroup<"shorten-64-to-32">;
def : DiagGroup<"sign-promo">;
@@ -480,6 +485,7 @@ def UnusedFunction : DiagGroup<"unused-function", [UnneededInternalDecl]>;
def UnusedMemberFunction : DiagGroup<"unused-member-function",
[UnneededMemberFunction]>;
def UnusedLabel : DiagGroup<"unused-label">;
+def UnusedLambdaCapture : DiagGroup<"unused-lambda-capture">;
def UnusedParameter : DiagGroup<"unused-parameter">;
def UnusedResult : DiagGroup<"unused-result">;
def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">;
@@ -602,6 +608,7 @@ def Conversion : DiagGroup<"conversion",
[BoolConversion,
ConstantConversion,
EnumConversion,
+ BitFieldEnumConversion,
FloatConversion,
Shorten64To32,
IntConversion,
@@ -617,8 +624,9 @@ def Unused : DiagGroup<"unused",
[UnusedArgument, UnusedFunction, UnusedLabel,
// UnusedParameter, (matches GCC's behavior)
// UnusedMemberFunction, (clean-up llvm before enabling)
- UnusedPrivateField, UnusedLocalTypedef,
- UnusedValue, UnusedVariable, UnusedPropertyIvar]>,
+ UnusedPrivateField, UnusedLambdaCapture,
+ UnusedLocalTypedef, UnusedValue, UnusedVariable,
+ UnusedPropertyIvar]>,
DiagCategory<"Unused Entity Issue">;
// Format settings.
@@ -881,7 +889,7 @@ def BackendOptimizationFailure : DiagGroup<"pass-failed">;
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">;
-// AddressSanitizer frontent instrumentation remarks.
+// AddressSanitizer frontend instrumentation remarks.
def SanitizeAddressRemarks : DiagGroup<"sanitize-address">;
// Issues with serialized diagnostics.
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index fcd04a0be187..f5f70cb5e7d3 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -84,6 +84,7 @@ class DiagnosticMapping {
unsigned IsPragma : 1;
unsigned HasNoWarningAsError : 1;
unsigned HasNoErrorAsFatal : 1;
+ unsigned WasUpgradedFromWarning : 1;
public:
static DiagnosticMapping Make(diag::Severity Severity, bool IsUser,
@@ -94,6 +95,7 @@ public:
Result.IsPragma = IsPragma;
Result.HasNoWarningAsError = 0;
Result.HasNoErrorAsFatal = 0;
+ Result.WasUpgradedFromWarning = 0;
return Result;
}
@@ -103,11 +105,33 @@ public:
bool isUser() const { return IsUser; }
bool isPragma() const { return IsPragma; }
+ bool isErrorOrFatal() const {
+ return getSeverity() == diag::Severity::Error ||
+ getSeverity() == diag::Severity::Fatal;
+ }
+
bool hasNoWarningAsError() const { return HasNoWarningAsError; }
void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; }
bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; }
void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; }
+
+ /// Whether this mapping attempted to map the diagnostic to a warning, but
+ /// was overruled because the diagnostic was already mapped to an error or
+ /// fatal error.
+ bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; }
+ void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; }
+
+ /// Serialize the bits that aren't based on context.
+ unsigned serializeBits() const {
+ return (WasUpgradedFromWarning << 3) | Severity;
+ }
+ static diag::Severity deserializeSeverity(unsigned Bits) {
+ return (diag::Severity)(Bits & 0x7);
+ }
+ static bool deserializeUpgradedFromWarning(unsigned Bits) {
+ return Bits >> 3;
+ }
};
/// \brief Used for handling and querying diagnostic IDs.
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 0943feae950e..aebf8a9f3574 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -176,6 +176,9 @@ def warn_gcc_attribute_location : Warning<
def warn_attribute_no_decl : Warning<
"attribute %0 ignored, because it is not attached to a declaration">,
InGroup<IgnoredAttributes>;
+def err_ms_attributes_not_enabled : Error<
+ "'__declspec' attributes are not enabled; use '-fdeclspec' or "
+ "'-fms-extensions' to enable support for __declspec attributes">;
def err_expected_method_body : Error<"expected method body">;
def err_declspec_after_virtspec : Error<
"'%0' qualifier may not appear after the virtual specifier '%1'">;
@@ -361,8 +364,6 @@ def ext_decomp_decl_empty : ExtWarn<
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
"method type specifier must start with '-' or '+'">;
-def err_objc_no_attributes_on_category : Error<
- "attributes may not be specified on a category">;
def err_objc_missing_end : Error<"missing '@end'">;
def note_objc_container_start : Note<
"%select{class|protocol|category|class extension|implementation"
@@ -435,6 +436,13 @@ def err_declaration_does_not_declare_param : Error<
"declaration does not declare a parameter">;
def err_no_matching_param : Error<"parameter named %0 is missing">;
+/// Objective-C++ parser diagnostics
+def err_expected_token_instead_of_objcxx_keyword : Error<
+ "expected %0; %1 is a keyword in Objective-C++">;
+def err_expected_member_name_or_semi_objcxx_keyword : Error<
+ "expected member name or ';' after declaration specifiers; "
+ "%0 is a keyword in Objective-C++">;
+
/// C++ parser diagnostics
def err_invalid_operator_on_type : Error<
"cannot use %select{dot|arrow}0 operator on a type">;
@@ -669,9 +677,6 @@ def warn_static_inline_explicit_inst_ignored : Warning<
// Constructor template diagnostics.
def err_out_of_line_constructor_template_id : Error<
"out-of-line constructor for %0 cannot have template arguments">;
-def err_out_of_line_template_id_type_names_constructor : Error<
- "qualified reference to %0 is a constructor name rather than a "
- "%select{template name|type}1 wherever a constructor can be declared">;
def err_expected_qualified_after_typename : Error<
"expected a qualified name after 'typename'">;
@@ -859,6 +864,12 @@ def err_availability_query_repeated_platform: Error<
def err_availability_query_repeated_star : Error<
"'*' query has already been specified">;
+// External source symbol attribute
+def err_external_source_symbol_expected_keyword : Error<
+ "expected 'language', 'defined_in', or 'generated_declaration'">;
+def err_external_source_symbol_duplicate_clause : Error<
+ "duplicate %0 clause in an 'external_source_symbol' attribute">;
+
// Type safety attributes
def err_type_safety_unknown_flag : Error<
"invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">;
@@ -1036,6 +1047,16 @@ def err_pragma_loop_missing_argument : Error<
def err_pragma_loop_invalid_option : Error<
"%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
"vectorize_width, interleave, interleave_count, unroll, unroll_count, or distribute">;
+
+def err_pragma_fp_invalid_option : Error<
+ "%select{invalid|missing}0 option%select{ %1|}0; expected contract">;
+def err_pragma_fp_invalid_argument : Error<
+ "unexpected argument '%0' to '#pragma clang fp %1'; "
+ "expected 'on', 'fast' or 'off'">;
+def err_pragma_fp_scope : Error<
+ "'#pragma clang fp' can only appear at file scope or at the start of a "
+ "compound statement">;
+
def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c9343519e38b..9b2cfe495ce2 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -259,6 +259,9 @@ def err_anyx86_interrupt_attribute : Error<
"a pointer as the first parameter|a %2 type as the second parameter}1">;
def err_anyx86_interrupt_called : Error<
"interrupt service routine cannot be called directly">;
+def warn_arm_interrupt_calling_convention : Warning<
+ "call to function without interrupt attribute could clobber interruptee's VFP registers">,
+ InGroup<Extra>;
def warn_mips_interrupt_attribute : Warning<
"MIPS 'interrupt' attribute only applies to functions that have "
"%select{no parameters|a 'void' return type}0">,
@@ -316,6 +319,9 @@ def warn_unneeded_member_function : Warning<
InGroup<UnneededMemberFunction>, DefaultIgnore;
def warn_unused_private_field: Warning<"private field %0 is not used">,
InGroup<UnusedPrivateField>, DefaultIgnore;
+def warn_unused_lambda_capture: Warning<"lambda capture %0 is not "
+ "%select{used|required to be captured for this use}1">,
+ InGroup<UnusedLambdaCapture>, DefaultIgnore;
def warn_parameter_size: Warning<
"%0 is a large (%1 bytes) pass-by-value argument; "
@@ -363,7 +369,9 @@ def warn_decl_shadow :
"local variable|"
"variable in %2|"
"static data member of %2|"
- "field of %2}1">,
+ "field of %2|"
+ "typedef in %2|"
+ "type alias in %2}1">,
InGroup<Shadow>, DefaultIgnore;
def warn_decl_shadow_uncaptured_local :
Warning<warn_decl_shadow.Text>,
@@ -1201,8 +1209,9 @@ def warn_cxx98_compat_unelaborated_friend_type : Warning<
def err_qualified_friend_not_found : Error<
"no function named %0 with type %1 was found in the specified scope">;
def err_introducing_special_friend : Error<
- "must use a qualified name when declaring a %select{constructor|"
- "destructor|conversion operator}0 as a friend">;
+ "%plural{[0,2]:must use a qualified name when declaring|3:cannot declare}0"
+ " a %select{constructor|destructor|conversion operator|deduction guide}0 "
+ "as a friend">;
def err_tagless_friend_type_template : Error<
"friend type templates must use an elaborated type">;
def err_no_matching_local_friend : Error<
@@ -1447,6 +1456,15 @@ def err_nested_name_spec_is_not_class : Error<
def ext_nested_name_spec_is_enum : ExtWarn<
"use of enumeration in a nested name specifier is a C++11 extension">,
InGroup<CXX11>;
+def err_out_of_line_qualified_id_type_names_constructor : Error<
+ "qualified reference to %0 is a constructor name rather than a "
+ "%select{template name|type}1 in this context">;
+def ext_out_of_line_qualified_id_type_names_constructor : ExtWarn<
+ "ISO C++ specifies that "
+ "qualified reference to %0 is a constructor name rather than a "
+ "%select{template name|type}1 in this context, despite preceding "
+ "%select{'typename'|'template'}2 keyword">, SFINAEFailure,
+ InGroup<DiagGroup<"injected-class-name">>;
// C++ class members
def err_storageclass_invalid_for_member : Error<
@@ -1608,7 +1626,14 @@ def err_covariant_return_type_class_type_more_qualified : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (class type %1 is more qualified than class "
"type %2">;
-
+
+// C++ implicit special member functions
+def note_in_declaration_of_implicit_special_member : Note<
+ "while declaring the implicit "
+ "%select{default constructor|copy constructor|move constructor|"
+ "copy assignment operator|move assignment operator|destructor}1"
+ " for %0">;
+
// C++ constructors
def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
def err_invalid_qualified_constructor : Error<
@@ -1664,8 +1689,8 @@ def err_init_conversion_failed : Error<
"cannot initialize %select{a variable|a parameter|return object|an "
"exception object|a member subobject|an array element|a new value|a value|a "
"base class|a constructor delegation|a vector element|a block element|a "
- "complex element|a lambda capture|a compound literal initializer|a "
- "related result|a parameter of CF audited function}0 "
+ "block element|a complex element|a lambda capture|a compound literal "
+ "initializer|a related result|a parameter of CF audited function}0 "
"%diff{of type $ with an %select{rvalue|lvalue}2 of type $|"
"with an %select{rvalue|lvalue}2 of incompatible type}1,3"
"%select{|: different classes%diff{ ($ vs $)|}5,6"
@@ -1791,8 +1816,9 @@ def note_uninit_fixit_remove_cond : Note<
"remove the %select{'%1' if its condition|condition if it}0 "
"is always %select{false|true}2">;
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
-def err_list_init_in_parens : Error<"list-initializer for non-class type %0 "
- "must not be parenthesized">;
+def err_list_init_in_parens : Error<
+ "cannot initialize %select{non-class|reference}0 type %1 with a "
+ "parenthesized initializer list">;
def warn_unsequenced_mod_mod : Warning<
"multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
@@ -1833,8 +1859,8 @@ def warn_cxx98_compat_temp_copy : Warning<
InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore;
def err_selected_explicit_constructor : Error<
"chosen constructor is explicit in copy-initialization">;
-def note_constructor_declared_here : Note<
- "constructor declared here">;
+def note_explicit_ctor_deduction_guide_here : Note<
+ "explicit %select{constructor|deduction guide}0 declared here">;
// C++11 decltype
def err_decltype_in_declarator : Error<
@@ -1845,8 +1871,8 @@ def warn_cxx98_compat_auto_type_specifier : Warning<
"'auto' type specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_auto_variable_cannot_appear_in_own_initializer : Error<
- "variable %0 declared with %select{'auto'|'decltype(auto)'|'__auto_type'}1 "
- "type cannot appear in its own initializer">;
+ "variable %0 declared with deduced type %1 "
+ "cannot appear in its own initializer">;
def err_binding_cannot_appear_in_own_initializer : Error<
"binding %0 cannot appear in the initializer of its own "
"decomposition declaration">;
@@ -1855,20 +1881,29 @@ def err_illegal_decl_array_of_auto : Error<
def err_new_array_of_auto : Error<
"cannot allocate array of 'auto'">;
def err_auto_not_allowed : Error<
- "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed "
+ "%select{'auto'|'decltype(auto)'|'__auto_type'|"
+ "use of "
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}2 %3 requires template arguments; "
+ "argument deduction}0 not allowed "
"%select{in function prototype"
"|in non-static struct member|in struct member"
"|in non-static union member|in union member"
"|in non-static class member|in interface member"
- "|in exception declaration|in template parameter|in block literal"
+ "|in exception declaration|in template parameter until C++1z|in block literal"
"|in template argument|in typedef|in type alias|in function return type"
"|in conversion function type|here|in lambda parameter"
- "|in type allocated by 'new'|in K&R-style function parameter}1"
- "%select{|||||||| until C++1z||||||||||}1">;
+ "|in type allocated by 'new'|in K&R-style function parameter"
+ "|in template parameter|in friend declaration}1">;
+def err_dependent_deduced_tst : Error<
+ "typename specifier refers to "
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}0 member in %1; "
+ "argument deduction not allowed here">;
def err_auto_not_allowed_var_inst : Error<
"'auto' variable template instantiation is not allowed">;
def err_auto_var_requires_init : Error<
- "declaration of variable %0 with type %1 requires an initializer">;
+ "declaration of variable %0 with deduced type %1 requires an initializer">;
def err_auto_new_requires_ctor_arg : Error<
"new expression for type %0 requires a constructor argument">;
def err_auto_new_list_init : Error<
@@ -1898,8 +1933,13 @@ def err_auto_var_deduction_failure_from_init_list : Error<
def err_auto_new_deduction_failure : Error<
"new expression for type %0 has incompatible constructor argument of type %1">;
def err_auto_different_deductions : Error<
- "'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration "
- "of %2 and deduced as %3 in declaration of %4">;
+ "%select{'auto'|'decltype(auto)'|'__auto_type'|template arguments}0 "
+ "deduced as %1 in declaration of %2 and "
+ "deduced as %3 in declaration of %4">;
+def err_auto_non_deduced_not_alone : Error<
+ "%select{function with deduced return type|"
+ "declaration with trailing return type}0 "
+ "must be the only declaration in its group">;
def err_implied_std_initializer_list_not_found : Error<
"cannot deduce type of initializer list because std::initializer_list was "
"not found; include <initializer_list>">;
@@ -1915,6 +1955,8 @@ def err_auto_bitfield : Error<
"cannot pass bit-field as __auto_type initializer in C">;
// C++1y decltype(auto) type
+def err_decltype_auto_invalid : Error<
+ "'decltype(auto)' not allowed here">;
def err_decltype_auto_cannot_be_combined : Error<
"'decltype(auto)' cannot be combined with other type specifiers">;
def err_decltype_auto_function_declarator_not_declaration : Error<
@@ -1925,6 +1967,56 @@ def err_decltype_auto_compound_type : Error<
def err_decltype_auto_initializer_list : Error<
"cannot deduce 'decltype(auto)' from initializer list">;
+// C++1z deduced class template specialization types
+def err_deduced_class_template_compound_type : Error<
+ "cannot %select{form pointer to|form reference to|form array of|"
+ "form function returning|use parentheses when declaring variable with}0 "
+ "deduced class template specialization type">;
+def err_deduced_non_class_template_specialization_type : Error<
+ "%select{<error>|function template|variable template|alias template|"
+ "template template parameter|template}0 %1 requires template arguments; "
+ "argument deduction only allowed for class templates">;
+def err_deduced_class_template_ctor_ambiguous : Error<
+ "ambiguous deduction for template arguments of %0">;
+def err_deduced_class_template_ctor_no_viable : Error<
+ "no viable constructor or deduction guide for deduction of "
+ "template arguments of %0">;
+def err_deduced_class_template_incomplete : Error<
+ "template %0 has no definition and no %select{|viable }1deduction guides "
+ "for deduction of template arguments">;
+def err_deduced_class_template_deleted : Error<
+ "class template argument deduction for %0 selected a deleted constructor">;
+def err_deduced_class_template_explicit : Error<
+ "class template argument deduction for %0 selected an explicit "
+ "%select{constructor|deduction guide}1 for copy-list-initialization">;
+def err_deduction_guide_no_trailing_return_type : Error<
+ "deduction guide declaration without trailing return type">;
+def err_deduction_guide_bad_trailing_return_type : Error<
+ "deduced type %1 of deduction guide is not %select{|written as }2"
+ "a specialization of template %0">;
+def err_deduction_guide_with_complex_decl : Error<
+ "cannot specify any part of a return type in the "
+ "declaration of a deduction guide">;
+def err_deduction_guide_invalid_specifier : Error<
+ "deduction guide cannot be declared '%0'">;
+def err_deduction_guide_name_not_class_template : Error<
+ "cannot specify deduction guide for "
+ "%select{<error>|function template|variable template|alias template|"
+ "template template parameter|dependent template name}0 %1">;
+def err_deduction_guide_wrong_scope : Error<
+ "deduction guide must be declared in the same scope as template %q0">;
+def err_deduction_guide_defines_function : Error<
+ "deduction guide cannot have a function definition">;
+def err_deduction_guide_explicit_mismatch : Error<
+ "deduction guide is %select{not |}0declared 'explicit' but "
+ "previous declaration was%select{ not|}0">;
+def err_deduction_guide_specialized : Error<"deduction guide cannot be "
+ "%select{explicitly instantiated|explicitly specialized}0">;
+def err_deduction_guide_template_not_deducible : Error<
+ "deduction guide template contains "
+ "%select{a template parameter|template parameters}0 that cannot be "
+ "deduced">;
+
// C++1y deduced return types
def err_auto_fn_deduction_failure : Error<
"cannot deduce return type %0 from returned value of type %1">;
@@ -1950,6 +2042,9 @@ def override_keyword_hides_virtual_member_function : Error<
"%select{function|functions}1">;
def err_function_marked_override_not_overriding : Error<
"%0 marked 'override' but does not override any member functions">;
+def warn_destructor_marked_not_override_overriding : Warning <
+ "%0 overrides a destructor but is not marked 'override'">,
+ InGroup<CXX11WarnOverrideDestructor>, DefaultIgnore;
def warn_function_marked_not_override_overriding : Warning <
"%0 overrides a member function but is not marked 'override'">,
InGroup<CXX11WarnOverrideMethod>;
@@ -2215,6 +2310,9 @@ def err_concept_specialized : Error<
"%select{function|variable}0 concept cannot be "
"%select{explicitly instantiated|explicitly specialized|partially specialized}1">;
+def err_template_different_associated_constraints : Error<
+ "associated constraints differ in template redeclaration">;
+
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
"'%0' type specifier is incompatible with C++98">,
@@ -2261,7 +2359,7 @@ def warn_unsupported_target_attribute
InGroup<IgnoredAttributes>;
def err_attribute_unsupported
: Error<"%0 attribute is not supported for this target">;
-// The err_*_attribute_argument_not_int are seperate because they're used by
+// The err_*_attribute_argument_not_int are separate because they're used by
// VerifyIntegerConstantExpression.
def err_aligned_attribute_argument_not_int : Error<
"'aligned' attribute requires integer constant">;
@@ -2659,7 +2757,8 @@ def warn_attribute_wrong_decl_type : Warning<
"|functions, methods, enums, and classes"
"|structs, classes, variables, functions, and inline namespaces"
"|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members"
- "|classes and enumerations}1">,
+ "|classes and enumerations"
+ "|named declarations}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
@@ -3132,7 +3231,8 @@ def err_attribute_regparm_invalid_number : Error<
"'regparm' parameter must be between 0 and %0 inclusive">;
def err_attribute_not_supported_in_lang : Error<
"%0 attribute is not supported in %select{C|C++|Objective-C}1">;
-
+def err_attribute_not_supported_on_arch
+ : Error<"%0 attribute is not supported on '%1'">;
// Clang-Specific Attributes
def warn_attribute_iboutlet : Warning<
@@ -3380,7 +3480,7 @@ def note_ovl_candidate_disabled_by_function_cond_attr : Note<
def note_ovl_candidate_disabled_by_extension : Note<
"candidate disabled due to OpenCL extension">;
def err_addrof_function_disabled_by_enable_if_attr : Error<
- "cannot take address of function %0 becuase it has one or more "
+ "cannot take address of function %0 because it has one or more "
"non-tautological enable_if conditions">;
def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note<
"candidate function made ineligible by enable_if">;
@@ -3789,11 +3889,13 @@ def err_template_decl_ref : Error<
// C++ Template Argument Lists
def err_template_missing_args : Error<
- "use of class template %0 requires template arguments">;
+ "use of "
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}0 %1 requires template arguments">;
def err_template_arg_list_different_arity : Error<
"%select{too few|too many}0 template arguments for "
- "%select{class template|function template|template template parameter"
- "|template}1 %2">;
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}1 %2">;
def note_template_decl_here : Note<"template is declared here">;
def err_template_arg_must_be_type : Error<
"template argument for template type parameter must be a type">;
@@ -4063,7 +4165,7 @@ def ext_partial_specs_not_deducible : ExtWarn<
"%select{a template parameter|template parameters}1 that cannot be "
"deduced; this partial specialization will never be used">,
DefaultError, InGroup<DiagGroup<"unusable-partial-specialization">>;
-def note_partial_spec_unused_parameter : Note<
+def note_non_deducible_parameter : Note<
"non-deducible template parameter %0">;
def err_partial_spec_ordering_ambiguous : Error<
"ambiguous partial specializations of %0">;
@@ -4286,6 +4388,8 @@ def note_typename_refers_here : Note<
"referenced member %0 is declared here">;
def err_typename_missing : Error<
"missing 'typename' prior to dependent type name '%0%1'">;
+def err_typename_missing_template : Error<
+ "missing 'typename' prior to dependent type template name '%0%1'">;
def ext_typename_missing : ExtWarn<
"missing 'typename' prior to dependent type name '%0%1'">,
InGroup<DiagGroup<"typename-missing">>;
@@ -4304,7 +4408,7 @@ def err_template_kw_refers_to_non_template : Error<
"%0 following the 'template' keyword does not refer to a template">;
def err_template_kw_refers_to_class_template : Error<
"'%0%1' instantiated to a class template, not a function template">;
-def note_referenced_class_template : Error<
+def note_referenced_class_template : Note<
"class template declared here">;
def err_template_kw_missing : Error<
"missing 'template' keyword prior to dependent template name '%0%1'">;
@@ -4808,6 +4912,21 @@ def warn_bitfield_width_exceeds_type_width: Warning<
def warn_anon_bitfield_width_exceeds_type_width : Warning<
"width of anonymous bit-field (%0 bits) exceeds width of its type; value "
"will be truncated to %1 bit%s1">, InGroup<BitFieldWidth>;
+def warn_bitfield_too_small_for_enum : Warning<
+ "bit-field %0 is not wide enough to store all enumerators of %1">,
+ InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def note_widen_bitfield : Note<
+ "widen this field to %0 bits to store all values of %1">;
+def warn_unsigned_bitfield_assigned_signed_enum : Warning<
+ "assigning value of signed enum type %1 to unsigned bit-field %0; "
+ "negative enumerators of enum %1 will be converted to positive values">,
+ InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def warn_signed_bitfield_enum_conversion : Warning<
+ "signed bit-field %0 needs an extra bit to represent the largest positive "
+ "enumerators of %1">,
+ InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def note_change_bitfield_sign : Note<
+ "consider making the bitfield type %select{unsigned|signed}0">;
def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
@@ -5164,7 +5283,7 @@ def err_arc_inconsistent_property_ownership : Error<
def warn_block_capture_autoreleasing : Warning<
"block captures an autoreleasing out-parameter, which may result in "
"use-after-free bugs">,
- InGroup<BlockCaptureAutoReleasing>, DefaultIgnore;
+ InGroup<BlockCaptureAutoReleasing>;
def note_declare_parameter_autoreleasing : Note<
"declare the parameter __autoreleasing explicitly to suppress this warning">;
def note_declare_parameter_strong : Note<
@@ -5725,8 +5844,8 @@ def err_this_static_member_func : Error<
def err_invalid_member_use_in_static_method : Error<
"invalid use of member %0 in static member function">;
def err_invalid_qualified_function_type : Error<
- "%select{static |non-}0member function %select{of type %2 |}1"
- "cannot have '%3' qualifier">;
+ "%select{non-member function|static member function|deduction guide}0 "
+ "%select{of type %2 |}1cannot have '%3' qualifier">;
def err_compound_qualified_function_type : Error<
"%select{block pointer|pointer|reference}0 to function type %select{%2 |}1"
"cannot have '%3' qualifier">;
@@ -5750,8 +5869,8 @@ def err_builtin_func_cast_more_than_one_arg : Error<
"function-style cast to a builtin type can only take one argument">;
def err_value_init_for_array_type : Error<
"array types cannot be value-initialized">;
-def err_value_init_for_function_type : Error<
- "function types cannot be value-initialized">;
+def err_init_for_function_type : Error<
+ "cannot create object of function type %0">;
def warn_format_nonliteral_noargs : Warning<
"format string is not a string literal (potentially insecure)">,
InGroup<FormatSecurity>;
@@ -5916,6 +6035,12 @@ def warn_objc_circular_container : Warning<
"adding '%0' to '%1' might cause circular dependency in container">,
InGroup<DiagGroup<"objc-circular-container">>;
def note_objc_circular_container_declared_here : Note<"'%0' declared here">;
+def warn_objc_unsafe_perform_selector : Warning<
+ "%0 is incompatible with selectors that return a "
+ "%select{struct|union|vector}1 type">,
+ InGroup<DiagGroup<"objc-unsafe-perform-selector">>;
+def note_objc_unsafe_perform_selector_method_declared_here : Note<
+ "method %0 that returns %1 declared here">;
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
@@ -7001,7 +7126,7 @@ def err_incomplete_type_used_in_type_trait_expr : Error<
def err_require_constant_init_failed : Error<
"variable does not have a constant initializer">;
def note_declared_required_constant_init_here : Note<
- "required by 'require_constant_initializer' attribute here">;
+ "required by 'require_constant_initialization' attribute here">;
def err_dimension_expr_not_constant_integer : Error<
"dimension expression does not evaluate to a constant unsigned int">;
@@ -7899,6 +8024,8 @@ def err_x86_builtin_32_bit_tgt : Error<
"this builtin is only available on x86-64 targets">;
def err_x86_builtin_invalid_rounding : Error<
"invalid rounding argument">;
+def err_x86_builtin_invalid_scale : Error<
+ "scale argument must be 1, 2, 4, or 8">;
def err_builtin_longjmp_unsupported : Error<
"__builtin_longjmp is not supported for the current target">;
@@ -8113,6 +8240,8 @@ def err_opencl_ptrptr_kernel_param : Error<
def err_kernel_arg_address_space : Error<
"pointer arguments to kernel functions must reside in '__global', "
"'__constant' or '__local' address space">;
+def err_opencl_ext_vector_component_invalid_length : Error<
+ "vector component access has invalid length %0. Supported: 1,2,3,4,8,16.">;
def err_opencl_function_variable : Error<
"%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">;
def err_static_function_scope : Error<
@@ -8158,9 +8287,9 @@ def err_opencl_return_value_with_address_space : Error<
"return value cannot be qualified with address space">;
def err_opencl_constant_no_init : Error<
"variable in constant address space must be initialized">;
-def err_atomic_init_constant : Error<
- "atomic variable can only be assigned to a compile time constant"
- " in the declaration statement in the program scope">;
+def err_opencl_atomic_init: Error<
+ "atomic variable can be %select{assigned|initialized}0 to a variable only "
+ "in global address space">;
def err_opencl_implicit_vector_conversion : Error<
"implicit conversions between vector types (%0 and %1) are not permitted">;
def err_opencl_invalid_type_array : Error<
@@ -8210,6 +8339,8 @@ def err_opencl_invalid_block_declaration : Error<
"invalid block variable declaration - must be %select{const qualified|initialized}0">;
def err_opencl_extern_block_declaration : Error<
"invalid block variable declaration - using 'extern' storage class is disallowed">;
+def err_opencl_block_ref_block : Error<
+ "cannot refer to a block inside block">;
// OpenCL v2.0 s6.13.9 - Address space qualifier functions.
def err_opencl_builtin_to_addr_arg_num : Error<
@@ -8227,9 +8358,9 @@ def err_opencl_enqueue_kernel_local_size_args : Error<
def err_opencl_enqueue_kernel_invalid_local_size_type : Error<
"illegal call to enqueue_kernel, parameter needs to be specified as integer type">;
def err_opencl_enqueue_kernel_blocks_non_local_void_args : Error<
- "blocks used in device side enqueue are expected to have parameters of type 'local void*'">;
+ "blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'">;
def err_opencl_enqueue_kernel_blocks_no_args : Error<
- "blocks in this form of device side enqueue call are expected to have have no parameters">;
+ "blocks with parameters are not accepted in this prototype of enqueue_kernel call">;
// OpenCL v2.2 s2.1.2.3 - Vector Component Access
def ext_opencl_ext_vector_type_rgba_selector: ExtWarn<
@@ -8708,8 +8839,7 @@ let CategoryName = "Coroutines Issue" in {
def err_return_in_coroutine : Error<
"return statement not allowed in coroutine; did you mean 'co_return'?">;
def note_declared_coroutine_here : Note<
- "function is a coroutine due to use of "
- "'%select{co_await|co_yield|co_return}0' here">;
+ "function is a coroutine due to use of '%0' here">;
def err_coroutine_objc_method : Error<
"Objective-C methods as coroutines are not yet supported">;
def err_coroutine_unevaluated_context : Error<
@@ -8721,24 +8851,38 @@ def err_coroutine_invalid_func_context : Error<
"|a copy assignment operator|a move assignment operator|the 'main' function"
"|a constexpr function|a function with a deduced return type"
"|a varargs function}0">;
-def err_implied_std_coroutine_traits_not_found : Error<
- "you need to include <experimental/coroutine> before defining a coroutine">;
+def err_implied_coroutine_type_not_found : Error<
+ "%0 type was not found; include <experimental/coroutine> before defining "
+ "a coroutine">;
+def err_malformed_std_coroutine_handle : Error<
+ "std::experimental::coroutine_handle must be a class template">;
+def err_coroutine_handle_missing_member : Error<
+ "std::experimental::coroutine_handle missing a member named '%0'">;
def err_malformed_std_coroutine_traits : Error<
"'std::experimental::coroutine_traits' must be a class template">;
def err_implied_std_coroutine_traits_promise_type_not_found : Error<
"this function cannot be a coroutine: %q0 has no member named 'promise_type'">;
def err_implied_std_coroutine_traits_promise_type_not_class : Error<
"this function cannot be a coroutine: %0 is not a class">;
-def err_coroutine_traits_missing_specialization : Error<
+def err_coroutine_promise_type_incomplete : Error<
+ "this function cannot be a coroutine: %0 is an incomplete type">;
+def err_coroutine_type_missing_specialization : Error<
"this function cannot be a coroutine: missing definition of "
"specialization %q0">;
-def err_implied_std_current_exception_not_found : Error<
- "you need to include <exception> before defining a coroutine that implicitly "
- "uses 'set_exception'">;
-def err_malformed_std_current_exception : Error<
- "'std::current_exception' must be a function">;
def err_coroutine_promise_return_ill_formed : Error<
"%0 declares both 'return_value' and 'return_void'">;
+def note_coroutine_promise_implicit_await_transform_required_here : Note<
+ "call to 'await_transform' implicitly required by 'co_await' here">;
+def note_coroutine_promise_call_implicitly_required : Note<
+ "call to '%select{initial_suspend|final_suspend}0' implicitly "
+ "required by the %select{initial suspend point|final suspend point}0">;
+def err_coroutine_promise_unhandled_exception_required : Error<
+ "%0 is required to declare the member 'unhandled_exception()'">;
+def warn_coroutine_promise_unhandled_exception_required_with_exceptions : Warning<
+ "%0 is required to declare the member 'unhandled_exception()' when exceptions are enabled">,
+ InGroup<Coroutine>;
+def err_coroutine_promise_get_return_object_on_allocation_failure : Error<
+ "%0: 'get_return_object_on_allocation_failure()' must be a static member function">;
}
let CategoryName = "Documentation Issue" in {
@@ -8905,4 +9049,9 @@ def ext_warn_gnu_final : ExtWarn<
"__final is a GNU extension, consider using C++11 final">,
InGroup<GccCompat>;
+def warn_shadow_field :
+ Warning<"non-static data member '%0' of '%1' shadows member inherited from type '%2'">,
+ InGroup<ShadowField>, DefaultIgnore;
+def note_shadow_field : Note<"declared here">;
+
} // end of sema component.
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index 066a1f5fa68f..4af4c18ced33 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -117,6 +117,57 @@ def note_module_odr_violation_different_definitions : Note<
def err_module_odr_violation_different_instantiations : Error<
"instantiation of %q0 is different in different modules">;
+def err_module_odr_violation_mismatch_decl : Error<
+ "%q0 has different definitions in different modules; first difference is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{end of class|public access specifier|private access specifier|"
+ "protected access specifier|static assert|field|method}3">;
+def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
+ "%select{end of class|public access specifier|private access specifier|"
+ "protected access specifier|static assert|field|method}1">;
+
+def err_module_odr_violation_mismatch_decl_diff : Error<
+ "%q0 has different definitions in different modules; first difference is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "static assert with condition|"
+ "static assert with message|"
+ "static assert with %select{|no }4message|"
+ "field %4|"
+ "field %4 with type %5|"
+ "%select{non-|}5bitfield %4|"
+ "bitfield %4 with one width expression|"
+ "%select{non-|}5mutable field %4|"
+ "field %4 with %select{no|an}5 initalizer|"
+ "field %4 with an initializer|"
+ "method %4|"
+ "method %4 is %select{not deleted|deleted}5|"
+ "method %4 is %select{|pure }5%select{not virtual|virtual}6|"
+ "method %4 is %select{not static|static}5|"
+ "method %4 is %select{not volatile|volatile}5|"
+ "method %4 is %select{not const|const}5|"
+ "method %4 is %select{not inline|inline}5}3">;
+
+def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
+ "%select{"
+ "static assert with different condition|"
+ "static assert with different message|"
+ "static assert with %select{|no }2message|"
+ "field %2|"
+ "field %2 with type %3|"
+ "%select{non-|}3bitfield %2|"
+ "bitfield %2 with different width expression|"
+ "%select{non-|}3mutable field %2|"
+ "field %2 with %select{no|an}3 initializer|"
+ "field %2 with a different initializer|"
+ "method %2|"
+ "method %2 is %select{not deleted|deleted}3|"
+ "method %2 is %select{|pure }3%select{not virtual|virtual}4|"
+ "method %2 is %select{not static|static}3|"
+ "method %2 is %select{not volatile|volatile}3|"
+ "method %2 is %select{not const|const}3|"
+ "method %2 is %select{not inline|inline}3}1">;
+
def warn_module_uses_date_time : Warning<
"%select{precompiled header|module}0 uses __DATE__ or __TIME__">,
InGroup<DiagGroup<"pch-date-time">>;
@@ -125,6 +176,11 @@ def warn_duplicate_module_file_extension : Warning<
"duplicate module file extension block name '%0'">,
InGroup<ModuleFileExtension>;
+def warn_module_system_bit_conflict : Warning<
+ "module file '%0' was validated as a system module and is now being imported "
+ "as a non-system module; any difference in diagnostic options will be ignored">,
+ InGroup<ModuleConflict>;
+
} // let CategoryName
} // let Component
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 3001d0b1b0c7..a5fd14104d3c 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -280,7 +280,11 @@ public:
bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
/// \brief Return true if this token is a keyword in the specified language.
- bool isKeyword(const LangOptions &LangOpts);
+ bool isKeyword(const LangOptions &LangOpts) const;
+
+ /// \brief Return true if this token is a C++ keyword in the specified
+ /// language.
+ bool isCPlusPlusKeyword(const LangOptions &LangOpts) const;
/// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
/// associate arbitrary metadata with this token.
@@ -818,6 +822,7 @@ public:
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
CXXOperator##Name,
#include "clang/Basic/OperatorKinds.def"
+ CXXDeductionGuide,
CXXLiteralOperator,
CXXUsingDirective,
NUM_EXTRA_KINDS
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index d944a9d78ab9..c8e197299754 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -107,7 +107,7 @@ LANGOPT(WChar , 1, CPlusPlus, "wchar_t keyword")
LANGOPT(DeclSpecKeyword , 1, 0, "__declspec keyword")
BENIGN_LANGOPT(DollarIdents , 1, 1, "'$' in identifiers")
BENIGN_LANGOPT(AsmPreprocessor, 1, 0, "preprocessor in asm mode")
-BENIGN_LANGOPT(GNUMode , 1, 1, "GNU extensions")
+LANGOPT(GNUMode , 1, 1, "GNU extensions")
LANGOPT(GNUKeywords , 1, 1, "GNU keywords")
BENIGN_LANGOPT(ImplicitInt, 1, !C99 && !CPlusPlus, "C89 implicit 'int'")
LANGOPT(Digraphs , 1, 0, "digraphs")
@@ -201,6 +201,8 @@ LANGOPT(SizedDeallocation , 1, 0, "sized deallocation")
LANGOPT(AlignedAllocation , 1, 0, "aligned allocation")
LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'")
LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts")
+BENIGN_LANGOPT(ModulesCodegen , 1, 0, "Modules code generation")
+BENIGN_LANGOPT(ModulesDebugInfo , 1, 0, "Modules debug info")
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form")
@@ -215,7 +217,8 @@ BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger Objective-C literals and su
BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants")
LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math")
-LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT")
+/// \brief FP_CONTRACT mode (on/off/fast).
+ENUM_LANGOPT(DefaultFPContractMode, FPContractModeKind, 2, FPC_Off, "FP contraction type")
LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")
LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")
@@ -261,6 +264,8 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
"field padding (0: none, 1:least "
"aggressive, 2: more aggressive)")
+LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation")
+
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 10635b11225e..20a0e5845602 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -88,6 +88,12 @@ public:
MSVC2015 = 19
};
+ enum FPContractModeKind {
+ FPC_Off, // Form fused FP ops only where result will not be affected.
+ FPC_On, // Form fused FP ops according to FP_CONTRACT rules.
+ FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
+ };
+
public:
/// \brief Set of enabled sanitizers.
SanitizerSet Sanitize;
@@ -96,6 +102,16 @@ public:
/// (files, functions, variables) should not be instrumented.
std::vector<std::string> SanitizerBlacklistFiles;
+ /// \brief Paths to the XRay "always instrument" files specifying which
+ /// objects (files, functions, variables) should be imbued with the XRay
+ /// "always instrument" attribute.
+ std::vector<std::string> XRayAlwaysInstrumentFiles;
+
+ /// \brief Paths to the XRay "never instrument" files specifying which
+ /// objects (files, functions, variables) should be imbued with the XRay
+ /// "never instrument" attribute.
+ std::vector<std::string> XRayNeverInstrumentFiles;
+
clang::ObjCRuntime ObjCRuntime;
std::string ObjCConstantStringClass;
@@ -170,17 +186,45 @@ public:
/// \brief Is this a libc/libm function that is no longer recognized as a
/// builtin because a -fno-builtin-* option has been specified?
bool isNoBuiltinFunc(StringRef Name) const;
+
+ /// \brief True if any ObjC types may have non-trivial lifetime qualifiers.
+ bool allowsNonTrivialObjCLifetimeQualifiers() const {
+ return ObjCAutoRefCount || ObjCWeak;
+ }
};
/// \brief Floating point control options
class FPOptions {
public:
- unsigned fp_contract : 1;
+ FPOptions() : fp_contract(LangOptions::FPC_Off) {}
+
+ // Used for serializing.
+ explicit FPOptions(unsigned I)
+ : fp_contract(static_cast<LangOptions::FPContractModeKind>(I)) {}
+
+ explicit FPOptions(const LangOptions &LangOpts)
+ : fp_contract(LangOpts.getDefaultFPContractMode()) {}
+
+ bool allowFPContractWithinStatement() const {
+ return fp_contract == LangOptions::FPC_On;
+ }
+ bool allowFPContractAcrossStatement() const {
+ return fp_contract == LangOptions::FPC_Fast;
+ }
+ void setAllowFPContractWithinStatement() {
+ fp_contract = LangOptions::FPC_On;
+ }
+ void setAllowFPContractAcrossStatement() {
+ fp_contract = LangOptions::FPC_Fast;
+ }
+ void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; }
- FPOptions() : fp_contract(0) {}
+ /// Used to serialize this.
+ unsigned getInt() const { return fp_contract; }
- FPOptions(const LangOptions &LangOpts) :
- fp_contract(LangOpts.DefaultFPContract) {}
+private:
+ /// Adjust BinaryOperator::FPFeatures to match the bit-field size of this.
+ unsigned fp_contract : 2;
};
/// \brief Describes the kind of translation unit being processed.
diff --git a/include/clang/Basic/MemoryBufferCache.h b/include/clang/Basic/MemoryBufferCache.h
new file mode 100644
index 000000000000..c79c3c40e4eb
--- /dev/null
+++ b/include/clang/Basic/MemoryBufferCache.h
@@ -0,0 +1,80 @@
+//===- MemoryBufferCache.h - Cache for loaded memory buffers ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H
+#define LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringMap.h"
+#include <memory>
+
+namespace llvm {
+class MemoryBuffer;
+} // end namespace llvm
+
+namespace clang {
+
+/// Manage memory buffers across multiple users.
+///
+/// Ensures that multiple users have a consistent view of each buffer. This is
+/// used by \a CompilerInstance when building PCMs to ensure that each \a
+/// ModuleManager sees the same files.
+///
+/// \a finalizeCurrentBuffers() should be called before creating a new user.
+/// This locks in the current buffers, ensuring that no buffer that has already
+/// been accessed can be purged, preventing use-after-frees.
+class MemoryBufferCache : public llvm::RefCountedBase<MemoryBufferCache> {
+ struct BufferEntry {
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
+
+ /// Track the timeline of when this was added to the cache.
+ unsigned Index;
+ };
+
+ /// Cache of buffers.
+ llvm::StringMap<BufferEntry> Buffers;
+
+ /// Monotonically increasing index.
+ unsigned NextIndex = 0;
+
+ /// Bumped to prevent "older" buffers from being removed.
+ unsigned FirstRemovableIndex = 0;
+
+public:
+ /// Store the Buffer under the Filename.
+ ///
+ /// \pre There is not already buffer is not already in the cache.
+ /// \return a reference to the buffer as a convenience.
+ llvm::MemoryBuffer &addBuffer(llvm::StringRef Filename,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer);
+
+ /// Try to remove a buffer from the cache.
+ ///
+ /// \return false on success, iff \c !isBufferFinal().
+ bool tryToRemoveBuffer(llvm::StringRef Filename);
+
+ /// Get a pointer to the buffer if it exists; else nullptr.
+ llvm::MemoryBuffer *lookupBuffer(llvm::StringRef Filename);
+
+ /// Check whether the buffer is final.
+ ///
+ /// \return true iff \a finalizeCurrentBuffers() has been called since the
+ /// buffer was added. This prevents buffers from being removed.
+ bool isBufferFinal(llvm::StringRef Filename);
+
+ /// Finalize the current buffers in the cache.
+ ///
+ /// Should be called when creating a new user to ensure previous uses aren't
+ /// invalidated.
+ void finalizeCurrentBuffers();
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 31c5c7ec9ca8..8fcb0e8b056a 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -42,7 +42,17 @@ class IdentifierInfo;
/// \brief Describes the name of a module.
typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId;
-
+
+/// The signature of a module, which is a hash of the AST content.
+struct ASTFileSignature : std::array<uint32_t, 5> {
+ ASTFileSignature(std::array<uint32_t, 5> S = {{0}})
+ : std::array<uint32_t, 5>(std::move(S)) {}
+
+ explicit operator bool() const {
+ return *this != std::array<uint32_t, 5>({{0}});
+ }
+};
+
/// \brief Describes a module or submodule.
class Module {
public:
@@ -65,7 +75,7 @@ public:
llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella;
/// \brief The module signature.
- uint64_t Signature;
+ ASTFileSignature Signature;
/// \brief The name of the umbrella entry, as written in the module map.
std::string UmbrellaAsWritten;
diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h
index 78fc89988245..8dc259c7ab66 100644
--- a/include/clang/Basic/ObjCRuntime.h
+++ b/include/clang/Basic/ObjCRuntime.h
@@ -326,6 +326,20 @@ public:
}
}
+ /// Are the empty collection symbols available?
+ bool hasEmptyCollections() const {
+ switch (getKind()) {
+ default:
+ return false;
+ case MacOSX:
+ return getVersion() >= VersionTuple(10, 11);
+ case iOS:
+ return getVersion() >= VersionTuple(9);
+ case WatchOS:
+ return getVersion() >= VersionTuple(2);
+ }
+ }
+
/// \brief Try to parse an Objective-C runtime specification from the given
/// string.
///
diff --git a/include/clang/Basic/OpenCLImageTypes.def b/include/clang/Basic/OpenCLImageTypes.def
index 1ca12f683beb..0efed996ab96 100644
--- a/include/clang/Basic/OpenCLImageTypes.def
+++ b/include/clang/Basic/OpenCLImageTypes.def
@@ -66,7 +66,7 @@ IMAGE_WRITE_TYPE(image2d_msaa, OCLImage2dMSAA, "cl_khr_gl_msaa_sharing")
IMAGE_WRITE_TYPE(image2d_array_msaa, OCLImage2dArrayMSAA, "cl_khr_gl_msaa_sharing")
IMAGE_WRITE_TYPE(image2d_msaa_depth, OCLImage2dMSAADepth, "cl_khr_gl_msaa_sharing")
IMAGE_WRITE_TYPE(image2d_array_msaa_depth, OCLImage2dArrayMSAADepth, "cl_khr_gl_msaa_sharing")
-IMAGE_WRITE_TYPE(image3d, OCLImage3d, "")
+IMAGE_WRITE_TYPE(image3d, OCLImage3d, "cl_khr_3d_image_writes")
IMAGE_READ_WRITE_TYPE(image1d, OCLImage1d, "")
IMAGE_READ_WRITE_TYPE(image1d_array, OCLImage1dArray, "")
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
index 60b9fcef9219..e00333153f9b 100644
--- a/include/clang/Basic/OpenMPKinds.h
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -234,6 +234,11 @@ bool isOpenMPTaskingDirective(OpenMPDirectiveKind Kind);
/// directives that need loop bound sharing across loops outlined in nested
/// functions
bool isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind);
+
+/// Return the captured regions of an OpenMP directive.
+void getOpenMPCaptureRegions(
+ llvm::SmallVectorImpl<OpenMPDirectiveKind> &CaptureRegions,
+ OpenMPDirectiveKind DKind);
}
#endif
diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
index c81273ea5fd4..c574045e139a 100644
--- a/include/clang/Basic/Sanitizers.def
+++ b/include/clang/Basic/Sanitizers.def
@@ -64,6 +64,11 @@ SANITIZER("function", Function)
SANITIZER("integer-divide-by-zero", IntegerDivideByZero)
SANITIZER("nonnull-attribute", NonnullAttribute)
SANITIZER("null", Null)
+SANITIZER("nullability-arg", NullabilityArg)
+SANITIZER("nullability-assign", NullabilityAssign)
+SANITIZER("nullability-return", NullabilityReturn)
+SANITIZER_GROUP("nullability", Nullability,
+ NullabilityArg | NullabilityAssign | NullabilityReturn)
SANITIZER("object-size", ObjectSize)
SANITIZER("return", Return)
SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute)
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 006cf3dc950c..f0fe4c27062e 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -321,8 +321,7 @@ public:
}
/// \brief Comparison function class, useful for sorting FullSourceLocs.
- struct BeforeThanCompare : public std::binary_function<FullSourceLoc,
- FullSourceLoc, bool> {
+ struct BeforeThanCompare {
bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const {
return lhs.isBeforeInTranslationUnitThan(rhs);
}
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 369a36f3dca6..33952f83ff23 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -82,11 +82,12 @@ namespace clang {
/// \brief Structure that packs information about the type specifiers that
/// were written in a particular type specifier sequence.
struct WrittenBuiltinSpecs {
- /*DeclSpec::TST*/ unsigned Type : 5;
+ static_assert(TST_error < 1 << 6, "Type bitfield not wide enough for TST");
+ /*DeclSpec::TST*/ unsigned Type : 6;
/*DeclSpec::TSS*/ unsigned Sign : 2;
/*DeclSpec::TSW*/ unsigned Width : 2;
unsigned ModeAttr : 1;
- };
+ };
/// \brief A C++ access specifier (public, private, protected), plus the
/// special value "none" which means different things in different contexts.
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 67a5ab773aa6..0d21845fbf8b 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -43,7 +43,7 @@ def ObjCAtSynchronizedStmt : Stmt;
def ObjCForCollectionStmt : Stmt;
def ObjCAutoreleasePoolStmt : Stmt;
-// C++ statments
+// C++ statements
def CXXCatchStmt : Stmt;
def CXXTryStmt : Stmt;
def CXXForRangeStmt : Stmt;
@@ -150,6 +150,7 @@ def CXXFoldExpr : DStmt<Expr>;
// C++ Coroutines TS expressions
def CoroutineSuspendExpr : DStmt<Expr, 1>;
def CoawaitExpr : DStmt<CoroutineSuspendExpr>;
+def DependentCoawaitExpr : DStmt<Expr>;
def CoyieldExpr : DStmt<CoroutineSuspendExpr>;
// Obj-C Expressions.
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 208f8e8c7137..9bdb288eef4f 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -154,7 +154,7 @@ public:
/// typedef void* __builtin_va_list;
VoidPtrBuiltinVaList,
- /// __builtin_va_list as defind by the AArch64 ABI
+ /// __builtin_va_list as defined by the AArch64 ABI
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055a/IHI0055A_aapcs64.pdf
AArch64ABIBuiltinVaList,
@@ -168,7 +168,7 @@ public:
PowerABIBuiltinVaList,
/// __builtin_va_list as defined by the x86-64 ABI:
- /// http://www.x86-64.org/documentation/abi.pdf
+ /// http://refspecs.linuxbase.org/elf/x86_64-abi-0.21.pdf
X86_64ABIBuiltinVaList,
/// __builtin_va_list as defined by ARM AAPCS ABI
@@ -823,8 +823,9 @@ public:
/// \brief Set forced language options.
///
/// Apply changes to the target information with respect to certain
- /// language options which change the target configuration.
- virtual void adjust(const LangOptions &Opts);
+ /// language options which change the target configuration and adjust
+ /// the language based on the target options where applicable.
+ virtual void adjust(LangOptions &Opts);
/// \brief Adjust target options based on codegen options.
virtual void adjustTargetOptions(const CodeGenOptions &CGOpts,
@@ -1032,6 +1033,21 @@ public:
return LangAS::opencl_global;
}
+ /// \returns Target specific vtbl ptr address space.
+ virtual unsigned getVtblPtrAddressSpace() const {
+ return 0;
+ }
+
+ /// \returns If a target requires an address within a target specific address
+ /// space \p AddressSpace to be converted in order to be used, then return the
+ /// corresponding target specific DWARF address space.
+ ///
+ /// \returns Otherwise return None and no conversion will be emitted in the
+ /// DWARF.
+ virtual Optional<unsigned> getDWARFAddressSpace(unsigned AddressSpace) const {
+ return None;
+ }
+
/// \brief Check the target is valid after it is fully initialized.
virtual bool validateTarget(DiagnosticsEngine &Diags) const {
return true;
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 104b053a14af..48e0c33f0e86 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -432,6 +432,7 @@ TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX)
TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX)
TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX)
+TYPE_TRAIT_1(__is_aggregate, IsAggregate, KEYCXX)
TYPE_TRAIT_2(__is_base_of, IsBaseOf, KEYCXX)
TYPE_TRAIT_1(__is_class, IsClass, KEYCXX)
TYPE_TRAIT_2(__is_convertible_to, IsConvertibleTo, KEYCXX)
@@ -787,6 +788,8 @@ ANNOTATION(pragma_openmp_end)
// handles #pragma loop ... directives.
ANNOTATION(pragma_loop_hint)
+ANNOTATION(pragma_fp)
+
// Annotations for module import translated from #include etc.
ANNOTATION(module_include)
ANNOTATION(module_begin)
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index 730ecba3d4fa..ffe62559002e 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -31,6 +31,7 @@ namespace clang {
UTT_HasTrivialDestructor,
UTT_HasVirtualDestructor,
UTT_IsAbstract,
+ UTT_IsAggregate,
UTT_IsArithmetic,
UTT_IsArray,
UTT_IsClass,
diff --git a/include/clang/Basic/VirtualFileSystem.h b/include/clang/Basic/VirtualFileSystem.h
index 39dab6cbf045..e52b345e286c 100644
--- a/include/clang/Basic/VirtualFileSystem.h
+++ b/include/clang/Basic/VirtualFileSystem.h
@@ -161,7 +161,7 @@ public:
directory_iterator &increment(std::error_code &EC) {
assert(Impl && "attempting to increment past end");
EC = Impl->increment();
- if (EC || !Impl->CurrentEntry.isStatusKnown())
+ if (!Impl->CurrentEntry.isStatusKnown())
Impl.reset(); // Normalize the end iterator to Impl == nullptr.
return *this;
}
diff --git a/include/clang/Basic/XRayLists.h b/include/clang/Basic/XRayLists.h
new file mode 100644
index 000000000000..fe538289c3a6
--- /dev/null
+++ b/include/clang/Basic/XRayLists.h
@@ -0,0 +1,54 @@
+//===--- XRayLists.h - XRay automatic attribution ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters for always/never XRay instrumenting certain functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_XRAYLISTS_H
+#define LLVM_CLANG_BASIC_XRAYLISTS_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
+
+namespace clang {
+
+class XRayFunctionFilter {
+ std::unique_ptr<llvm::SpecialCaseList> AlwaysInstrument;
+ std::unique_ptr<llvm::SpecialCaseList> NeverInstrument;
+ SourceManager &SM;
+
+public:
+ XRayFunctionFilter(ArrayRef<std::string> AlwaysInstrumentPaths,
+ ArrayRef<std::string> NeverInstrumentPaths,
+ SourceManager &SM);
+
+ enum class ImbueAttribute {
+ NONE,
+ ALWAYS,
+ NEVER,
+ };
+
+ ImbueAttribute shouldImbueFunction(StringRef FunctionName) const;
+
+ ImbueAttribute
+ shouldImbueFunctionsInFile(StringRef Filename,
+ StringRef Category = StringRef()) const;
+
+ ImbueAttribute shouldImbueLocation(SourceLocation Loc,
+ StringRef Category = StringRef()) const;
+};
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index 5605fc6de2b6..ad8d679a1664 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -1362,7 +1362,7 @@ def SCALAR_SHL: SInst<"vshl", "sss", "SlSUl">;
def SCALAR_QSHL: SInst<"vqshl", "sss", "ScSsSiSlSUcSUsSUiSUl">;
// Scalar Saturating Rounding Shift Left
def SCALAR_QRSHL: SInst<"vqrshl", "sss", "ScSsSiSlSUcSUsSUiSUl">;
-// Scalar Shift Rouding Left
+// Scalar Shift Rounding Left
def SCALAR_RSHL: SInst<"vrshl", "sss", "SlSUl">;
////////////////////////////////////////////////////////////////////////////////
diff --git a/include/clang/CodeGen/BackendUtil.h b/include/clang/CodeGen/BackendUtil.h
index c6abc6e3f574..bb105cb533a4 100644
--- a/include/clang/CodeGen/BackendUtil.h
+++ b/include/clang/CodeGen/BackendUtil.h
@@ -15,6 +15,8 @@
#include <memory>
namespace llvm {
+ class BitcodeModule;
+ template <typename T> class Expected;
class Module;
class MemoryBufferRef;
}
@@ -44,6 +46,9 @@ namespace clang {
void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts,
llvm::MemoryBufferRef Buf);
+
+ llvm::Expected<llvm::BitcodeModule>
+ FindThinLTOModule(llvm::MemoryBufferRef MBRef);
}
#endif
diff --git a/include/clang/CodeGen/CodeGenABITypes.h b/include/clang/CodeGen/CodeGenABITypes.h
index e7b7435968fb..8ba769dfc3af 100644
--- a/include/clang/CodeGen/CodeGenABITypes.h
+++ b/include/clang/CodeGen/CodeGenABITypes.h
@@ -16,7 +16,7 @@
//
// It allows other clients, like LLDB, to determine the LLVM types that are
// actually used in function calls, which makes it possible to then determine
-// the acutal ABI locations (e.g. registers, stack locations, etc.) that
+// the actual ABI locations (e.g. registers, stack locations, etc.) that
// these parameters are stored in.
//
//===----------------------------------------------------------------------===//
diff --git a/include/clang/CodeGen/CodeGenAction.h b/include/clang/CodeGen/CodeGenAction.h
index cc38e243420b..5a18a9de030b 100644
--- a/include/clang/CodeGen/CodeGenAction.h
+++ b/include/clang/CodeGen/CodeGenAction.h
@@ -23,14 +23,36 @@ class BackendConsumer;
class CodeGenAction : public ASTFrontendAction {
private:
+ // Let BackendConsumer access LinkModule.
+ friend class BackendConsumer;
+
+ /// Info about module to link into a module we're generating.
+ struct LinkModule {
+ /// The module to link in.
+ std::unique_ptr<llvm::Module> Module;
+
+ /// If true, we set attributes on Module's functions according to our
+ /// CodeGenOptions and LangOptions, as though we were generating the
+ /// function ourselves.
+ bool PropagateAttrs;
+
+ /// If true, we use LLVM module internalizer.
+ bool Internalize;
+
+ /// Bitwise combination of llvm::LinkerFlags used when we link the module.
+ unsigned LinkFlags;
+ };
+
unsigned Act;
std::unique_ptr<llvm::Module> TheModule;
- // Vector of {Linker::Flags, Module*} pairs to specify bitcode
- // modules to link in using corresponding linker flags.
- SmallVector<std::pair<unsigned, llvm::Module *>, 4> LinkModules;
+
+ /// Bitcode modules to link in to our module.
+ SmallVector<LinkModule, 4> LinkModules;
llvm::LLVMContext *VMContext;
bool OwnsVMContext;
+ std::unique_ptr<llvm::Module> loadModule(llvm::MemoryBufferRef MBRef);
+
protected:
/// Create a new code generation action. If the optional \p _VMContext
/// parameter is supplied, the action uses it without taking ownership,
@@ -49,13 +71,6 @@ protected:
public:
~CodeGenAction() override;
- /// setLinkModule - Set the link module to be used by this action. If a link
- /// module is not provided, and CodeGenOptions::LinkBitcodeFile is non-empty,
- /// the action will load it from the specified file.
- void addLinkModule(llvm::Module *Mod, unsigned LinkFlags) {
- LinkModules.push_back(std::make_pair(LinkFlags, Mod));
- }
-
/// Take the generated LLVM module, for use after the action has been run.
/// The result may be null on failure.
std::unique_ptr<llvm::Module> takeModule();
diff --git a/include/clang/CodeGen/ConstantInitBuilder.h b/include/clang/CodeGen/ConstantInitBuilder.h
new file mode 100644
index 000000000000..113d86d82c10
--- /dev/null
+++ b/include/clang/CodeGen/ConstantInitBuilder.h
@@ -0,0 +1,561 @@
+//===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class provides a convenient interface for building complex
+// global initializers of the sort that are frequently required for
+// language ABIs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
+#define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalValue.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/CodeGen/ConstantInitFuture.h"
+
+#include <vector>
+
+namespace clang {
+namespace CodeGen {
+
+class CodeGenModule;
+
+/// A convenience builder class for complex constant initializers,
+/// especially for anonymous global structures used by various language
+/// runtimes.
+///
+/// The basic usage pattern is expected to be something like:
+/// ConstantInitBuilder builder(CGM);
+/// auto toplevel = builder.beginStruct();
+/// toplevel.addInt(CGM.SizeTy, widgets.size());
+/// auto widgetArray = builder.beginArray();
+/// for (auto &widget : widgets) {
+/// auto widgetDesc = widgetArray.beginStruct();
+/// widgetDesc.addInt(CGM.SizeTy, widget.getPower());
+/// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName()));
+/// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl()));
+/// widgetDesc.finishAndAddTo(widgetArray);
+/// }
+/// widgetArray.finishAndAddTo(toplevel);
+/// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
+/// /*constant*/ true);
+class ConstantInitBuilderBase {
+ struct SelfReference {
+ llvm::GlobalVariable *Dummy;
+ llvm::SmallVector<llvm::Constant*, 4> Indices;
+
+ SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {}
+ };
+ CodeGenModule &CGM;
+ llvm::SmallVector<llvm::Constant*, 16> Buffer;
+ std::vector<SelfReference> SelfReferences;
+ bool Frozen = false;
+
+ friend class ConstantInitFuture;
+ friend class ConstantAggregateBuilderBase;
+ template <class, class>
+ friend class ConstantAggregateBuilderTemplateBase;
+
+protected:
+ explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
+
+ ~ConstantInitBuilderBase() {
+ assert(Buffer.empty() && "didn't claim all values out of buffer");
+ assert(SelfReferences.empty() && "didn't apply all self-references");
+ }
+
+private:
+ llvm::GlobalVariable *createGlobal(llvm::Constant *initializer,
+ const llvm::Twine &name,
+ CharUnits alignment,
+ bool constant = false,
+ llvm::GlobalValue::LinkageTypes linkage
+ = llvm::GlobalValue::InternalLinkage,
+ unsigned addressSpace = 0);
+
+ ConstantInitFuture createFuture(llvm::Constant *initializer);
+
+ void setGlobalInitializer(llvm::GlobalVariable *GV,
+ llvm::Constant *initializer);
+
+ void resolveSelfReferences(llvm::GlobalVariable *GV);
+
+ void abandon(size_t newEnd);
+};
+
+/// A concrete base class for struct and array aggregate
+/// initializer builders.
+class ConstantAggregateBuilderBase {
+protected:
+ ConstantInitBuilderBase &Builder;
+ ConstantAggregateBuilderBase *Parent;
+ size_t Begin;
+ mutable size_t CachedOffsetEnd = 0;
+ bool Finished = false;
+ bool Frozen = false;
+ bool Packed = false;
+ mutable CharUnits CachedOffsetFromGlobal;
+
+ llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
+ return Builder.Buffer;
+ }
+
+ const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
+ return Builder.Buffer;
+ }
+
+ ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder,
+ ConstantAggregateBuilderBase *parent)
+ : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) {
+ if (parent) {
+ assert(!parent->Frozen && "parent already has child builder active");
+ parent->Frozen = true;
+ } else {
+ assert(!builder.Frozen && "builder already has child builder active");
+ builder.Frozen = true;
+ }
+ }
+
+ ~ConstantAggregateBuilderBase() {
+ assert(Finished && "didn't finish aggregate builder");
+ }
+
+ void markFinished() {
+ assert(!Frozen && "child builder still active");
+ assert(!Finished && "builder already finished");
+ Finished = true;
+ if (Parent) {
+ assert(Parent->Frozen &&
+ "parent not frozen while child builder active");
+ Parent->Frozen = false;
+ } else {
+ assert(Builder.Frozen &&
+ "builder not frozen while child builder active");
+ Builder.Frozen = false;
+ }
+ }
+
+public:
+ // Not copyable.
+ ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete;
+ ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &)
+ = delete;
+
+ // Movable, mostly to allow returning. But we have to write this out
+ // properly to satisfy the assert in the destructor.
+ ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other)
+ : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
+ CachedOffsetEnd(other.CachedOffsetEnd),
+ Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed),
+ CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) {
+ other.Finished = true;
+ }
+ ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other)
+ = delete;
+
+ /// Return the number of elements that have been added to
+ /// this struct or array.
+ size_t size() const {
+ assert(!this->Finished && "cannot query after finishing builder");
+ assert(!this->Frozen && "cannot query while sub-builder is active");
+ assert(this->Begin <= this->getBuffer().size());
+ return this->getBuffer().size() - this->Begin;
+ }
+
+ /// Return true if no elements have yet been added to this struct or array.
+ bool empty() const {
+ return size() == 0;
+ }
+
+ /// Abandon this builder completely.
+ void abandon() {
+ markFinished();
+ Builder.abandon(Begin);
+ }
+
+ /// Add a new value to this initializer.
+ void add(llvm::Constant *value) {
+ assert(value && "adding null value to constant initializer");
+ assert(!Finished && "cannot add more values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ Builder.Buffer.push_back(value);
+ }
+
+ /// Add an integer value of type size_t.
+ void addSize(CharUnits size);
+
+ /// Add an integer value of a specific type.
+ void addInt(llvm::IntegerType *intTy, uint64_t value,
+ bool isSigned = false) {
+ add(llvm::ConstantInt::get(intTy, value, isSigned));
+ }
+
+ /// Add a null pointer of a specific type.
+ void addNullPointer(llvm::PointerType *ptrTy) {
+ add(llvm::ConstantPointerNull::get(ptrTy));
+ }
+
+ /// Add a bitcast of a value to a specific type.
+ void addBitCast(llvm::Constant *value, llvm::Type *type) {
+ add(llvm::ConstantExpr::getBitCast(value, type));
+ }
+
+ /// Add a bunch of new values to this initializer.
+ void addAll(llvm::ArrayRef<llvm::Constant *> values) {
+ assert(!Finished && "cannot add more values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ Builder.Buffer.append(values.begin(), values.end());
+ }
+
+ /// Add a relative offset to the given target address, i.e. the
+ /// static difference between the target address and the address
+ /// of the relative offset. The target must be known to be defined
+ /// in the current linkage unit. The offset will have the given
+ /// integer type, which must be no wider than intptr_t. Some
+ /// targets may not fully support this operation.
+ void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) {
+ add(getRelativeOffset(type, target));
+ }
+
+ /// Add a relative offset to the target address, plus a small
+ /// constant offset. This is primarily useful when the relative
+ /// offset is known to be a multiple of (say) four and therefore
+ /// the tag can be used to express an extra two bits of information.
+ void addTaggedRelativeOffset(llvm::IntegerType *type,
+ llvm::Constant *address,
+ unsigned tag) {
+ llvm::Constant *offset = getRelativeOffset(type, address);
+ if (tag) {
+ offset = llvm::ConstantExpr::getAdd(offset,
+ llvm::ConstantInt::get(type, tag));
+ }
+ add(offset);
+ }
+
+ /// Return the offset from the start of the initializer to the
+ /// next position, assuming no padding is required prior to it.
+ ///
+ /// This operation will not succeed if any unsized placeholders are
+ /// currently in place in the initializer.
+ CharUnits getNextOffsetFromGlobal() const {
+ assert(!Finished && "cannot add more values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ return getOffsetFromGlobalTo(Builder.Buffer.size());
+ }
+
+ /// An opaque class to hold the abstract position of a placeholder.
+ class PlaceholderPosition {
+ size_t Index;
+ friend class ConstantAggregateBuilderBase;
+ PlaceholderPosition(size_t index) : Index(index) {}
+ };
+
+ /// Add a placeholder value to the structure. The returned position
+ /// can be used to set the value later; it will not be invalidated by
+ /// any intermediate operations except (1) filling the same position or
+ /// (2) finishing the entire builder.
+ ///
+ /// This is useful for emitting certain kinds of structure which
+ /// contain some sort of summary field, generaly a count, before any
+ /// of the data. By emitting a placeholder first, the structure can
+ /// be emitted eagerly.
+ PlaceholderPosition addPlaceholder() {
+ assert(!Finished && "cannot add more values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ Builder.Buffer.push_back(nullptr);
+ return Builder.Buffer.size() - 1;
+ }
+
+ /// Add a placeholder, giving the expected type that will be filled in.
+ PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType);
+
+ /// Fill a previously-added placeholder.
+ void fillPlaceholderWithInt(PlaceholderPosition position,
+ llvm::IntegerType *type, uint64_t value,
+ bool isSigned = false) {
+ fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned));
+ }
+
+ /// Fill a previously-added placeholder.
+ void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) {
+ assert(!Finished && "cannot change values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ llvm::Constant *&slot = Builder.Buffer[position.Index];
+ assert(slot == nullptr && "placeholder already filled");
+ slot = value;
+ }
+
+ /// Produce an address which will eventually point to the the next
+ /// position to be filled. This is computed with an indexed
+ /// getelementptr rather than by computing offsets.
+ ///
+ /// The returned pointer will have type T*, where T is the given
+ /// position.
+ llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
+
+ llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition(
+ llvm::SmallVectorImpl<llvm::Constant*> &indices) {
+ getGEPIndicesTo(indices, Builder.Buffer.size());
+ return indices;
+ }
+
+protected:
+ llvm::Constant *finishArray(llvm::Type *eltTy);
+ llvm::Constant *finishStruct(llvm::StructType *structTy);
+
+private:
+ void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
+ size_t position) const;
+
+ llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType,
+ llvm::Constant *target);
+
+ CharUnits getOffsetFromGlobalTo(size_t index) const;
+};
+
+template <class Impl, class Traits>
+class ConstantAggregateBuilderTemplateBase
+ : public Traits::AggregateBuilderBase {
+ using super = typename Traits::AggregateBuilderBase;
+public:
+ using InitBuilder = typename Traits::InitBuilder;
+ using ArrayBuilder = typename Traits::ArrayBuilder;
+ using StructBuilder = typename Traits::StructBuilder;
+ using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
+
+protected:
+ ConstantAggregateBuilderTemplateBase(InitBuilder &builder,
+ AggregateBuilderBase *parent)
+ : super(builder, parent) {}
+
+ Impl &asImpl() { return *static_cast<Impl*>(this); }
+
+public:
+ ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
+ return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy);
+ }
+
+ StructBuilder beginStruct(llvm::StructType *ty = nullptr) {
+ return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty);
+ }
+
+ /// Given that this builder was created by beginning an array or struct
+ /// component on the given parent builder, finish the array/struct
+ /// component and add it to the parent.
+ ///
+ /// It is an intentional choice that the parent is passed in explicitly
+ /// despite it being redundant with information already kept in the
+ /// builder. This aids in readability by making it easier to find the
+ /// places that add components to a builder, as well as "bookending"
+ /// the sub-builder more explicitly.
+ void finishAndAddTo(AggregateBuilderBase &parent) {
+ assert(this->Parent == &parent && "adding to non-parent builder");
+ parent.add(asImpl().finishImpl());
+ }
+
+ /// Given that this builder was created by beginning an array or struct
+ /// directly on a ConstantInitBuilder, finish the array/struct and
+ /// create a global variable with it as the initializer.
+ template <class... As>
+ llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) {
+ assert(!this->Parent && "finishing non-root builder");
+ return this->Builder.createGlobal(asImpl().finishImpl(),
+ std::forward<As>(args)...);
+ }
+
+ /// Given that this builder was created by beginning an array or struct
+ /// directly on a ConstantInitBuilder, finish the array/struct and
+ /// set it as the initializer of the given global variable.
+ void finishAndSetAsInitializer(llvm::GlobalVariable *global) {
+ assert(!this->Parent && "finishing non-root builder");
+ return this->Builder.setGlobalInitializer(global, asImpl().finishImpl());
+ }
+
+ /// Given that this builder was created by beginning an array or struct
+ /// directly on a ConstantInitBuilder, finish the array/struct and
+ /// return a future which can be used to install the initializer in
+ /// a global later.
+ ///
+ /// This is useful for allowing a finished initializer to passed to
+ /// an API which will build the global. However, the "future" preserves
+ /// a dependency on the original builder; it is an error to pass it aside.
+ ConstantInitFuture finishAndCreateFuture() {
+ assert(!this->Parent && "finishing non-root builder");
+ return this->Builder.createFuture(asImpl().finishImpl());
+ }
+};
+
+template <class Traits>
+class ConstantArrayBuilderTemplateBase
+ : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
+ Traits> {
+ using super =
+ ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>;
+
+public:
+ using InitBuilder = typename Traits::InitBuilder;
+ using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
+
+private:
+ llvm::Type *EltTy;
+
+ template <class, class>
+ friend class ConstantAggregateBuilderTemplateBase;
+
+protected:
+ ConstantArrayBuilderTemplateBase(InitBuilder &builder,
+ AggregateBuilderBase *parent,
+ llvm::Type *eltTy)
+ : super(builder, parent), EltTy(eltTy) {}
+
+private:
+ /// Form an array constant from the values that have been added to this
+ /// builder.
+ llvm::Constant *finishImpl() {
+ return AggregateBuilderBase::finishArray(EltTy);
+ }
+};
+
+/// A template class designed to allow other frontends to
+/// easily customize the builder classes used by ConstantInitBuilder,
+/// and thus to extend the API to work with the abstractions they
+/// prefer. This would probably not be necessary if C++ just
+/// supported extension methods.
+template <class Traits>
+class ConstantStructBuilderTemplateBase
+ : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
+ Traits> {
+ using super =
+ ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>;
+
+public:
+ using InitBuilder = typename Traits::InitBuilder;
+ using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
+
+private:
+ llvm::StructType *StructTy;
+
+ template <class, class>
+ friend class ConstantAggregateBuilderTemplateBase;
+
+protected:
+ ConstantStructBuilderTemplateBase(InitBuilder &builder,
+ AggregateBuilderBase *parent,
+ llvm::StructType *structTy)
+ : super(builder, parent), StructTy(structTy) {
+ if (structTy) this->Packed = structTy->isPacked();
+ }
+
+public:
+ void setPacked(bool packed) {
+ this->Packed = packed;
+ }
+
+ /// Use the given type for the struct if its element count is correct.
+ /// Don't add more elements after calling this.
+ void suggestType(llvm::StructType *structTy) {
+ if (this->size() == structTy->getNumElements()) {
+ StructTy = structTy;
+ }
+ }
+
+private:
+ /// Form an array constant from the values that have been added to this
+ /// builder.
+ llvm::Constant *finishImpl() {
+ return AggregateBuilderBase::finishStruct(StructTy);
+ }
+};
+
+/// A template class designed to allow other frontends to
+/// easily customize the builder classes used by ConstantInitBuilder,
+/// and thus to extend the API to work with the abstractions they
+/// prefer. This would probably not be necessary if C++ just
+/// supported extension methods.
+template <class Traits>
+class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase {
+protected:
+ ConstantInitBuilderTemplateBase(CodeGenModule &CGM)
+ : ConstantInitBuilderBase(CGM) {}
+
+public:
+ using InitBuilder = typename Traits::InitBuilder;
+ using ArrayBuilder = typename Traits::ArrayBuilder;
+ using StructBuilder = typename Traits::StructBuilder;
+
+ ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
+ return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy);
+ }
+
+ StructBuilder beginStruct(llvm::StructType *structTy = nullptr) {
+ return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy);
+ }
+};
+
+class ConstantInitBuilder;
+class ConstantStructBuilder;
+class ConstantArrayBuilder;
+
+struct ConstantInitBuilderTraits {
+ using InitBuilder = ConstantInitBuilder;
+ using AggregateBuilderBase = ConstantAggregateBuilderBase;
+ using ArrayBuilder = ConstantArrayBuilder;
+ using StructBuilder = ConstantStructBuilder;
+};
+
+/// The standard implementation of ConstantInitBuilder used in Clang.
+class ConstantInitBuilder
+ : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
+public:
+ explicit ConstantInitBuilder(CodeGenModule &CGM) :
+ ConstantInitBuilderTemplateBase(CGM) {}
+};
+
+/// A helper class of ConstantInitBuilder, used for building constant
+/// array initializers.
+class ConstantArrayBuilder
+ : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> {
+ template <class Traits>
+ friend class ConstantInitBuilderTemplateBase;
+
+ // The use of explicit qualification is a GCC workaround.
+ template <class Impl, class Traits>
+ friend class CodeGen::ConstantAggregateBuilderTemplateBase;
+
+ ConstantArrayBuilder(ConstantInitBuilder &builder,
+ ConstantAggregateBuilderBase *parent,
+ llvm::Type *eltTy)
+ : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {}
+};
+
+/// A helper class of ConstantInitBuilder, used for building constant
+/// struct initializers.
+class ConstantStructBuilder
+ : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
+ template <class Traits>
+ friend class ConstantInitBuilderTemplateBase;
+
+ // The use of explicit qualification is a GCC workaround.
+ template <class Impl, class Traits>
+ friend class CodeGen::ConstantAggregateBuilderTemplateBase;
+
+ ConstantStructBuilder(ConstantInitBuilder &builder,
+ ConstantAggregateBuilderBase *parent,
+ llvm::StructType *structTy)
+ : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/include/clang/CodeGen/ConstantInitFuture.h b/include/clang/CodeGen/ConstantInitFuture.h
new file mode 100644
index 000000000000..ef1a5d2f49af
--- /dev/null
+++ b/include/clang/CodeGen/ConstantInitFuture.h
@@ -0,0 +1,111 @@
+//===- ConstantInitFuture.h - "Future" constant initializers ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class defines the ConstantInitFuture class. This is split out
+// from ConstantInitBuilder.h in order to allow APIs to work with it
+// without having to include that entire header. This is particularly
+// important because it is often useful to be able to default-construct
+// a future in, say, a default argument.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_CONSTANTINITFUTURE_H
+#define LLVM_CLANG_CODEGEN_CONSTANTINITFUTURE_H
+
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/IR/Constant.h"
+
+// Forward-declare ConstantInitBuilderBase and give it a
+// PointerLikeTypeTraits specialization so that we can safely use it
+// in a PointerUnion below.
+namespace clang {
+namespace CodeGen {
+class ConstantInitBuilderBase;
+}
+}
+namespace llvm {
+template <>
+class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> {
+public:
+ using T = ::clang::CodeGen::ConstantInitBuilderBase*;
+
+ static inline void *getAsVoidPointer(T p) { return p; }
+ static inline T getFromVoidPointer(void *p) {return static_cast<T>(p);}
+ enum { NumLowBitsAvailable = 2 };
+};
+}
+
+namespace clang {
+namespace CodeGen {
+
+/// A "future" for a completed constant initializer, which can be passed
+/// around independently of any sub-builders (but not the original parent).
+class ConstantInitFuture {
+ using PairTy = llvm::PointerUnion<ConstantInitBuilderBase*, llvm::Constant*>;
+
+ PairTy Data;
+
+ friend class ConstantInitBuilderBase;
+ explicit ConstantInitFuture(ConstantInitBuilderBase *builder);
+
+public:
+ ConstantInitFuture() {}
+
+ /// A future can be explicitly created from a fixed initializer.
+ explicit ConstantInitFuture(llvm::Constant *initializer) : Data(initializer) {
+ assert(initializer && "creating null future");
+ }
+
+ /// Is this future non-null?
+ explicit operator bool() const { return bool(Data); }
+
+ /// Return the type of the initializer.
+ llvm::Type *getType() const;
+
+ /// Abandon this initializer.
+ void abandon();
+
+ /// Install the initializer into a global variable. This cannot
+ /// be called multiple times.
+ void installInGlobal(llvm::GlobalVariable *global);
+
+ void *getOpaqueValue() const { return Data.getOpaqueValue(); }
+ static ConstantInitFuture getFromOpaqueValue(void *value) {
+ ConstantInitFuture result;
+ result.Data = PairTy::getFromOpaqueValue(value);
+ return result;
+ }
+ enum {
+ NumLowBitsAvailable =
+ llvm::PointerLikeTypeTraits<PairTy>::NumLowBitsAvailable
+ };
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+namespace llvm {
+
+template <>
+class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> {
+public:
+ using T = ::clang::CodeGen::ConstantInitFuture;
+
+ static inline void *getAsVoidPointer(T future) {
+ return future.getOpaqueValue();
+ }
+ static inline T getFromVoidPointer(void *p) {
+ return T::getFromOpaqueValue(p);
+ }
+ enum { NumLowBitsAvailable = T::NumLowBitsAvailable };
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h
index 58638348653f..6f81ea9d6370 100644
--- a/include/clang/CodeGen/ModuleBuilder.h
+++ b/include/clang/CodeGen/ModuleBuilder.h
@@ -35,6 +35,7 @@ namespace clang {
namespace CodeGen {
class CodeGenModule;
+ class CGDebugInfo;
}
/// The primary public interface to the Clang code generator.
@@ -65,6 +66,9 @@ public:
/// CodeGenerator after releasing its module.
llvm::Module *ReleaseModule();
+ /// Return debug info code generator.
+ CodeGen::CGDebugInfo *getCGDebugInfo();
+
/// Given a mangled name, return a declaration which mangles that way
/// which has been added to this code generator via a Handle method.
///
diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake
index 55f0ca94dedc..6971b4e9f06d 100644
--- a/include/clang/Config/config.h.cmake
+++ b/include/clang/Config/config.h.cmake
@@ -38,6 +38,9 @@
/* Define if we have libxml2 */
#cmakedefine CLANG_HAVE_LIBXML ${CLANG_HAVE_LIBXML}
+/* Define if we have z3 and want to build it */
+#cmakedefine CLANG_ANALYZER_WITH_Z3 ${CLANG_ANALYZER_WITH_Z3}
+
/* Define if we have sys/resource.h (rlimits) */
#cmakedefine CLANG_HAVE_RLIMITS ${CLANG_HAVE_RLIMITS}
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index ab296ebb9f6a..ba09bccfe1c5 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -136,6 +136,8 @@ def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">,
let Flags = [CC1Option, CC1AsOption, NoDriverOption] in {
def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">;
+def debug_info_macro : Flag<["-"], "debug-info-macro">,
+ HelpText<"Emit macro debug information">;
def dwarf_version_EQ : Joined<["-"], "dwarf-version=">;
def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">;
def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
@@ -307,6 +309,11 @@ def fprofile_instrument_use_path_EQ :
def flto_visibility_public_std:
Flag<["-"], "flto-visibility-public-std">,
HelpText<"Use public LTO visibility for classes in std and stdext namespaces">;
+def flto_unit: Flag<["-"], "flto-unit">,
+ HelpText<"Emit IR to support LTO unit features (CFI, whole program vtable opt)">;
+def fno_lto_unit: Flag<["-"], "fno-lto-unit">;
+def fthin_link_bitcode_EQ : Joined<["-"], "fthin-link-bitcode=">,
+ HelpText<"Write minimized bitcode to <file> for the ThinLTO thin link only">;
//===----------------------------------------------------------------------===//
// Dependency Output Options
@@ -429,6 +436,14 @@ def fmodules_local_submodule_visibility :
Flag<["-"], "fmodules-local-submodule-visibility">,
HelpText<"Enforce name visibility rules across submodules of the same "
"top-level module.">;
+def fmodules_codegen :
+ Flag<["-"], "fmodules-codegen">,
+ HelpText<"Generate code for uses of this module that assumes an explicit "
+ "object file will be built for the module">;
+def fmodules_debuginfo :
+ Flag<["-"], "fmodules-debuginfo">,
+ HelpText<"Generate debug info for types in an object file built from this "
+ "module and do not generate them elsewhere">;
def fmodule_format_EQ : Joined<["-"], "fmodule-format=">,
HelpText<"Select the container format for clang modules and PCH. "
"Supported options are 'raw' and 'obj'.">;
@@ -466,6 +481,8 @@ def ast_list : Flag<["-"], "ast-list">,
HelpText<"Build ASTs and print the list of declaration node qualified names">;
def ast_dump : Flag<["-"], "ast-dump">,
HelpText<"Build ASTs and then debug dump them">;
+def ast_dump_all : Flag<["-"], "ast-dump-all">,
+ HelpText<"Build ASTs and then debug dump them, forcing deserialization">;
def ast_dump_lookups : Flag<["-"], "ast-dump-lookups">,
HelpText<"Build ASTs and then debug dump their name lookup tables">;
def ast_view : Flag<["-"], "ast-view">,
@@ -579,6 +596,8 @@ def pic_is_pie : Flag<["-"], "pic-is-pie">,
HelpText<"File is for a position independent executable">;
def fno_validate_pch : Flag<["-"], "fno-validate-pch">,
HelpText<"Disable validation of precompiled headers">;
+def fallow_pch_with_errors : Flag<["-"], "fallow-pch-with-compiler-errors">,
+ HelpText<"Accept a PCH file that was created with compiler errors">;
def dump_deserialized_pch_decls : Flag<["-"], "dump-deserialized-decls">,
HelpText<"Dump declarations that are deserialized from PCH, for testing">;
def error_on_deserialized_pch_decl : Separate<["-"], "error-on-deserialized-decl">,
@@ -643,6 +662,8 @@ def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">,
HelpText<"Set default MS calling convention">;
def finclude_default_header : Flag<["-"], "finclude-default-header">,
HelpText<"Include the default header file for OpenCL">;
+def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">,
+ HelpText<"Preserve 3-component vector type">;
// FIXME: Remove these entirely once functionality/tests have been excised.
def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>,
@@ -658,6 +679,8 @@ def nostdsysteminc : Flag<["-"], "nostdsysteminc">,
HelpText<"Disable standard system #include directories">;
def fdisable_module_hash : Flag<["-"], "fdisable-module-hash">,
HelpText<"Disable the module hash">;
+def fmodules_hash_content : Flag<["-"], "fmodules-hash-content">,
+ HelpText<"Enable hashing the content of a module file">;
def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"<directory>">,
HelpText<"Add directory to the C SYSTEM include search path">;
def objc_isystem : JoinedOrSeparate<["-"], "objc-isystem">,
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index 60048c49c0f7..9b6ab3a5ef2b 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-def cl_Group : OptionGroup<"<clang-cl options>">,
+def cl_Group : OptionGroup<"<clang-cl options>">, Flags<[CLOption]>,
HelpText<"CL.EXE COMPATIBILITY OPTIONS">;
def cl_compile_Group : OptionGroup<"<clang-cl compile-only options>">,
diff --git a/include/clang/Driver/ClangOptionDocs.td b/include/clang/Driver/ClangOptionDocs.td
new file mode 100644
index 000000000000..97c44692d257
--- /dev/null
+++ b/include/clang/Driver/ClangOptionDocs.td
@@ -0,0 +1,36 @@
+//==--- ClangOptionDocs.td - Option documentation -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+def GlobalDocumentation {
+ code Intro =[{..
+ -------------------------------------------------------------------
+ NOTE: This file is automatically generated by running clang-tblgen
+ -gen-opt-docs. Do not edit this file by hand!!
+ -------------------------------------------------------------------
+
+=====================================
+Clang command line argument reference
+=====================================
+.. contents::
+ :local:
+
+Introduction
+============
+
+This page lists the command line arguments currently supported by the
+GCC-compatible ``clang`` and ``clang++`` drivers.
+
+}];
+
+ string Program = "clang";
+ list<string> ExcludedFlags = ["HelpHidden", "NoDriverOption",
+ "CLOption", "Unsupported", "Ignored"];
+}
+
+include "Options.td"
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 0ce461ca61e1..1009754a15d5 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -14,6 +14,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Phases.h"
+#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/StringMap.h"
@@ -62,7 +63,7 @@ enum LTOKind {
/// Driver - Encapsulate logic for constructing compilation processes
/// from a set of gcc-driver-like command line arguments.
class Driver {
- llvm::opt::OptTable *Opts;
+ std::unique_ptr<llvm::opt::OptTable> Opts;
DiagnosticsEngine &Diags;
@@ -215,6 +216,11 @@ public:
/// Use lazy precompiled headers for PCH support.
unsigned CCCUsePCH : 1;
+ /// Force clang to emit reproducer for driver invocation. This is enabled
+ /// indirectly by setting FORCE_CLANG_DIAGNOSTICS_CRASH environment variable
+ /// or when using the -gen-reproducer driver flag.
+ unsigned GenReproducer : 1;
+
private:
/// Certain options suppress the 'no input files' warning.
unsigned SuppressMissingInputWarning : 1;
@@ -227,7 +233,7 @@ private:
/// This maps from the string representation of a triple to a ToolChain
/// created targeting that triple. The driver owns all the ToolChain objects
/// stored in it, and will clean them up when torn down.
- mutable llvm::StringMap<ToolChain *> ToolChains;
+ mutable llvm::StringMap<std::unique_ptr<ToolChain>> ToolChains;
private:
/// TranslateInputArgs - Create a new derived argument list from the input
@@ -264,7 +270,6 @@ public:
Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
- ~Driver();
/// @name Accessors
/// @{
@@ -304,13 +309,8 @@ public:
bool isSaveTempsObj() const { return SaveTemps == SaveTempsObj; }
bool embedBitcodeEnabled() const { return BitcodeEmbed != EmbedNone; }
- bool embedBitcodeInObject() const {
- // LTO has no object file output so ignore embed bitcode option in LTO.
- return (BitcodeEmbed == EmbedBitcode) && !isUsingLTO();
- }
- bool embedBitcodeMarkerOnly() const {
- return (BitcodeEmbed == EmbedMarker) && !isUsingLTO();
- }
+ bool embedBitcodeInObject() const { return (BitcodeEmbed == EmbedBitcode); }
+ bool embedBitcodeMarkerOnly() const { return (BitcodeEmbed == EmbedMarker); }
/// Compute the desired OpenMP runtime from the flags provided.
OpenMPRuntimeKind getOpenMPRuntime(const llvm::opt::ArgList &Args) const;
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index 54bed09e0adf..ff88256b8c0d 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_DRIVER_JOB_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Option/Option.h"
@@ -69,6 +70,9 @@ class Command {
/// file
std::string ResponseFileFlag;
+ /// See Command::setEnvironment
+ std::vector<const char *> Environment;
+
/// When a response file is needed, we try to put most arguments in an
/// exclusive file, while others remains as regular command line arguments.
/// This functions fills a vector with the regular command line arguments,
@@ -111,6 +115,12 @@ public:
InputFileList = std::move(List);
}
+ /// \brief Sets the environment to be used by the new process.
+ /// \param NewEnvironment An array of environment variables.
+ /// \remark If the environment remains unset, then the environment
+ /// from the parent process will be used.
+ void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment);
+
const char *getExecutable() const { return Executable; }
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index 2716fa9ae85e..57e4452f3e8c 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -10,6 +10,8 @@
#ifndef LLVM_CLANG_DRIVER_OPTIONS_H
#define LLVM_CLANG_DRIVER_OPTIONS_H
+#include <memory>
+
namespace llvm {
namespace opt {
class OptTable;
@@ -31,7 +33,8 @@ enum ClangFlags {
CLOption = (1 << 9),
CC1Option = (1 << 10),
CC1AsOption = (1 << 11),
- NoDriverOption = (1 << 12)
+ NoDriverOption = (1 << 12),
+ Ignored = (1 << 13)
};
enum ID {
@@ -44,7 +47,7 @@ enum ID {
};
}
-llvm::opt::OptTable *createDriverOptTable();
+std::unique_ptr<llvm::opt::OptTable> createDriverOptTable();
}
}
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 6be159fad694..36b24a02b2fe 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -33,6 +33,9 @@ def NoArgumentUnused : OptionFlag;
// lines that use it.
def Unsupported : OptionFlag;
+// Ignored - The option is unsupported, and the driver will silently ignore it.
+def Ignored : OptionFlag;
+
// CoreOption - This is considered a "core" Clang option, available in both
// clang and clang-cl modes.
def CoreOption : OptionFlag;
@@ -50,72 +53,150 @@ def CC1AsOption : OptionFlag;
// NoDriverOption - This option should not be accepted by the driver.
def NoDriverOption : OptionFlag;
+// A short name to show in documentation. The name will be interpreted as rST.
+class DocName<string name> { string DocName = name; }
+
+// A brief description to show in documentation, interpreted as rST.
+class DocBrief<code descr> { code DocBrief = descr; }
+
+// Indicates that this group should be flattened into its parent when generating
+// documentation.
+class DocFlatten { bit DocFlatten = 1; }
+
+// Indicates that this warning is ignored, but accepted with a warning for
+// GCC compatibility.
+class IgnoredGCCCompat : Flags<[HelpHidden]> {}
+
/////////
// Groups
+def Action_Group : OptionGroup<"<action group>">, DocName<"Actions">,
+ DocBrief<[{The action to perform on the input.}]>;
+
// Meta-group for options which are only used for compilation,
// and not linking etc.
-def CompileOnly_Group : OptionGroup<"<CompileOnly group>">;
-
-def Action_Group : OptionGroup<"<action group>">;
-
-def I_Group : OptionGroup<"<I group>">, Group<CompileOnly_Group>;
-def M_Group : OptionGroup<"<M group>">, Group<CompileOnly_Group>;
-def T_Group : OptionGroup<"<T group>">;
-def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>;
-def R_Group : OptionGroup<"<R group>">, Group<CompileOnly_Group>;
-def R_value_Group : OptionGroup<"<R (with value) group>">, Group<R_Group>;
-def W_Group : OptionGroup<"<W group>">, Group<CompileOnly_Group>;
-def W_value_Group : OptionGroup<"<W (with value) group>">, Group<W_Group>;
-def d_Group : OptionGroup<"<d group>">;
-def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>;
-def f_clang_Group : OptionGroup<"<f (clang-only) group>">, Group<CompileOnly_Group>;
-def g_Group : OptionGroup<"<g group>">;
-def gN_Group : OptionGroup<"<gN group>">, Group<g_Group>;
-def ggdbN_Group : OptionGroup<"<ggdbN group>">, Group<gN_Group>;
-def gTune_Group : OptionGroup<"<gTune group>">, Group<g_Group>;
-def g_flags_Group : OptionGroup<"<g flags group>">;
-def i_Group : OptionGroup<"<i group>">, Group<CompileOnly_Group>;
-def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>;
-def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>;
-def opencl_Group : OptionGroup<"<opencl group>">, Group<CompileOnly_Group>;
+def CompileOnly_Group : OptionGroup<"<CompileOnly group>">,
+ DocName<"Compilation flags">, DocBrief<[{
+Flags controlling the behavior of Clang during compilation. These flags have
+no effect during actions that do not perform compilation.}]>;
+
+def Preprocessor_Group : OptionGroup<"<Preprocessor group>">,
+ Group<CompileOnly_Group>,
+ DocName<"Preprocessor flags">, DocBrief<[{
+Flags controlling the behavior of the Clang preprocessor.}]>;
+
+def IncludePath_Group : OptionGroup<"<I/i group>">, Group<Preprocessor_Group>,
+ DocName<"Include path management">,
+ DocBrief<[{
+Flags controlling how ``#include``\s are resolved to files.}]>;
+
+def I_Group : OptionGroup<"<I group>">, Group<IncludePath_Group>, DocFlatten;
+def i_Group : OptionGroup<"<i group>">, Group<IncludePath_Group>, DocFlatten;
+def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>, DocFlatten;
+
+def M_Group : OptionGroup<"<M group>">, Group<Preprocessor_Group>,
+ DocName<"Dependency file generation">, DocBrief<[{
+Flags controlling generation of a dependency file for ``make``-like build
+systems.}]>;
+
+def d_Group : OptionGroup<"<d group>">, Group<Preprocessor_Group>,
+ DocName<"Dumping preprocessor state">, DocBrief<[{
+Flags allowing the state of the preprocessor to be dumped in various ways.}]>;
+
+def Diag_Group : OptionGroup<"<W/R group>">, Group<CompileOnly_Group>,
+ DocName<"Diagnostic flags">, DocBrief<[{
+Flags controlling which warnings, errors, and remarks Clang will generate.
+See the :doc:`full list of warning and remark flags <DiagnosticsReference>`.}]>;
+
+def R_Group : OptionGroup<"<R group>">, Group<Diag_Group>, DocFlatten;
+def R_value_Group : OptionGroup<"<R (with value) group>">, Group<R_Group>,
+ DocFlatten;
+def W_Group : OptionGroup<"<W group>">, Group<Diag_Group>, DocFlatten;
+def W_value_Group : OptionGroup<"<W (with value) group>">, Group<W_Group>,
+ DocFlatten;
+
+def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>,
+ DocName<"Target-independent compilation options">;
+
+def f_clang_Group : OptionGroup<"<f (clang-only) group>">,
+ Group<CompileOnly_Group>, DocFlatten;
+def pedantic_Group : OptionGroup<"<pedantic group>">, Group<f_Group>,
+ DocFlatten;
+def opencl_Group : OptionGroup<"<opencl group>">, Group<f_Group>,
+ DocName<"OpenCL flags">;
+
+def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>,
+ DocName<"Target-dependent compilation options">;
// Feature groups - these take command line options that correspond directly to
// target specific features and can be translated directly from command line
// options.
-def m_x86_Features_Group : OptionGroup<"<x86 features group>">,
- Group<m_Group>,
- Flags<[CoreOption]>;
-def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">,
- Group<m_Group>;
-def m_arm_Features_Group : OptionGroup<"<arm features group>">,
- Group<m_Group>;
def m_aarch64_Features_Group : OptionGroup<"<aarch64 features group>">,
- Group<m_Group>;
+ Group<m_Group>, DocName<"AARCH64">;
+def m_amdgpu_Features_Group : OptionGroup<"<amdgpu features group>">,
+ Group<m_Group>, DocName<"AMDGPU">;
+def m_arm_Features_Group : OptionGroup<"<arm features group>">,
+ Group<m_Group>, DocName<"ARM">;
+def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">,
+ Group<m_Group>, DocName<"Hexagon">;
def m_ppc_Features_Group : OptionGroup<"<ppc features group>">,
- Group<m_Group>;
+ Group<m_Group>, DocName<"PowerPC">;
def m_wasm_Features_Group : OptionGroup<"<wasm features group>">,
- Group<m_Group>;
-def m_amdgpu_Features_Group : OptionGroup<"<amdgpu features group>">,
- Group<m_Group>;
+ Group<m_Group>, DocName<"WebAssembly">;
+def m_x86_Features_Group : OptionGroup<"<x86 features group>">,
+ Group<m_Group>, Flags<[CoreOption]>, DocName<"X86">;
+
+def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_Group>,
+ Flags<[HelpHidden]>;
+
+def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>,
+ DocName<"Optimization level">, DocBrief<[{
+Flags controlling how much optimization should be performed.}]>;
+
+def DebugInfo_Group : OptionGroup<"<g group>">, Group<CompileOnly_Group>,
+ DocName<"Debug information generation">, DocBrief<[{
+Flags controlling how much and what kind of debug information should be
+generated.}]>;
+
+def g_Group : OptionGroup<"<g group>">, Group<DebugInfo_Group>,
+ DocName<"Kind and level of debug information">;
+def gN_Group : OptionGroup<"<gN group>">, Group<g_Group>,
+ DocName<"Debug level">;
+def ggdbN_Group : OptionGroup<"<ggdbN group>">, Group<gN_Group>, DocFlatten;
+def gTune_Group : OptionGroup<"<gTune group>">, Group<g_Group>,
+ DocName<"Debugger to tune debug information for">;
+def g_flags_Group : OptionGroup<"<g flags group>">, Group<DebugInfo_Group>,
+ DocName<"Debug information flags">;
+
+def StaticAnalyzer_Group : OptionGroup<"<Static analyzer group>">,
+ DocName<"Static analyzer flags">, DocBrief<[{
+Flags controlling the behavior of the Clang Static Analyzer.}]>;
-def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_Group>;
-def u_Group : OptionGroup<"<u group>">;
+// gfortran options that we recognize in the driver and pass along when
+// invoking GCC to compile Fortran code.
+def gfortran_Group : OptionGroup<"<gfortran group>">,
+ DocName<"Fortran compilation flags">, DocBrief<[{
+Flags that will be passed onto the ``gfortran`` compiler when Clang is given
+a Fortran input.}]>;
-def pedantic_Group : OptionGroup<"<pedantic group>">,
- Group<CompileOnly_Group>;
-def reserved_lib_Group : OptionGroup<"<reserved libs group>">;
+def Link_Group : OptionGroup<"<T/e/s/t/u group>">, DocName<"Linker flags">,
+ DocBrief<[{Flags that are passed on to the linker}]>;
+def T_Group : OptionGroup<"<T group>">, Group<Link_Group>, DocFlatten;
+def u_Group : OptionGroup<"<u group>">, Group<Link_Group>, DocFlatten;
+
+def reserved_lib_Group : OptionGroup<"<reserved libs group>">,
+ Flags<[Unsupported]>;
// Temporary groups for clang options which we know we don't support,
// but don't want to verbosely warn the user about.
def clang_ignored_f_Group : OptionGroup<"<clang ignored f group>">,
- Group<f_Group>;
+ Group<f_Group>, Flags<[Ignored]>;
def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">,
- Group<m_Group>;
+ Group<m_Group>, Flags<[Ignored]>;
// Group that ignores all gcc optimizations that won't be implemented
def clang_ignored_gcc_optimization_f_Group : OptionGroup<
- "<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>;
+ "<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>, Flags<[Ignored]>;
/////////
// Options
@@ -141,7 +222,7 @@ def clang_ignored_gcc_optimization_f_Group : OptionGroup<
// Developer Driver Options
-def internal_Group : OptionGroup<"<clang internal options>">;
+def internal_Group : OptionGroup<"<clang internal options>">, Flags<[HelpHidden]>;
def internal_driver_Group : OptionGroup<"<clang driver internal options>">,
Group<internal_Group>, HelpText<"DRIVER OPTIONS">;
def internal_debug_Group :
@@ -184,6 +265,8 @@ def arcmt_migrate_report_output : Separate<["-"], "arcmt-migrate-report-output">
def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">,
HelpText<"Emit ARC errors even if the migrator can fix them">,
Flags<[CC1Option]>;
+def gen_reproducer: Flag<["-"], "gen-reproducer">, InternalDebugOpt,
+ HelpText<"Auto-generates preprocessed source files and a reproduction script">;
def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>,
HelpText<"Run the migrator">;
@@ -236,23 +319,34 @@ def _HASH_HASH_HASH : Flag<["-"], "###">, Flags<[DriverOption, CoreOption]>,
HelpText<"Print (but do not run) the commands to run for this compilation">;
def _DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>,
Flags<[DriverOption, CoreOption]>;
-def A : JoinedOrSeparate<["-"], "A">, Flags<[RenderJoined]>;
-def B : JoinedOrSeparate<["-"], "B">;
-def CC : Flag<["-"], "CC">, Flags<[CC1Option]>;
-def C : Flag<["-"], "C">, Flags<[CC1Option]>;
-def D : JoinedOrSeparate<["-"], "D">, Group<CompileOnly_Group>, Flags<[CC1Option]>;
+def A : JoinedOrSeparate<["-"], "A">, Flags<[RenderJoined]>, Group<gfortran_Group>;
+def B : JoinedOrSeparate<["-"], "B">, MetaVarName<"<dir>">,
+ HelpText<"Add <dir> to search path for binaries and object files used implicitly">;
+def CC : Flag<["-"], "CC">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
+ HelpText<"Include comments from within macros in preprocessed output">;
+def C : Flag<["-"], "C">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
+ HelpText<"Include comments in preprocessed output">;
+def D : JoinedOrSeparate<["-"], "D">, Group<Preprocessor_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<macro>=<value>">,
+ HelpText<"Define <macro> to <value> (or 1 if <value> omitted)">;
def E : Flag<["-"], "E">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
- HelpText<"Only run the preprocessor">;
+ HelpText<"Only run the preprocessor">;
def F : JoinedOrSeparate<["-"], "F">, Flags<[RenderJoined,CC1Option]>,
HelpText<"Add directory to framework include search path">;
-def G : JoinedOrSeparate<["-"], "G">, Flags<[DriverOption]>;
-def G_EQ : Joined<["-"], "G=">, Flags<[DriverOption]>;
-def H : Flag<["-"], "H">, Flags<[CC1Option]>,
+def G : JoinedOrSeparate<["-"], "G">, Flags<[DriverOption]>, Group<m_Group>,
+ MetaVarName<"<size>">, HelpText<"Put objects of at most <size> bytes "
+ "into small data section (MIPS / Hexagon)">;
+def G_EQ : Joined<["-"], "G=">, Flags<[DriverOption]>, Group<m_Group>, Alias<G>;
+def H : Flag<["-"], "H">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
HelpText<"Show header includes and nesting depth">;
-def I_ : Flag<["-"], "I-">, Group<I_Group>;
-def I : JoinedOrSeparate<["-"], "I">, Group<I_Group>, Flags<[CC1Option,CC1AsOption]>,
+def I_ : Flag<["-"], "I-">, Group<I_Group>,
+ HelpText<"Restrict all prior -I flags to double-quoted inclusion and "
+ "remove current directory from include path">;
+def I : JoinedOrSeparate<["-"], "I">, Group<I_Group>,
+ Flags<[CC1Option,CC1AsOption]>, MetaVarName<"<dir>">,
HelpText<"Add directory to include search path">;
-def L : JoinedOrSeparate<["-"], "L">, Flags<[RenderJoined]>;
+def L : JoinedOrSeparate<["-"], "L">, Flags<[RenderJoined]>, Group<Link_Group>,
+ MetaVarName<"<dir>">, HelpText<"Add directory to library search path">;
def MD : Flag<["-"], "MD">, Group<M_Group>,
HelpText<"Write a depfile containing user and system headers">;
def MMD : Flag<["-"], "MMD">, Group<M_Group>,
@@ -276,9 +370,9 @@ def MT : JoinedOrSeparate<["-"], "MT">, Group<M_Group>, Flags<[CC1Option]>,
HelpText<"Specify name of main file output in depfile">;
def MV : Flag<["-"], "MV">, Group<M_Group>, Flags<[CC1Option]>,
HelpText<"Use NMake/Jom format for the depfile">;
-def Mach : Flag<["-"], "Mach">;
-def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[CC1Option]>;
-def O4 : Flag<["-"], "O4">, Group<O_Group>, Flags<[CC1Option]>;
+def Mach : Flag<["-"], "Mach">, Group<Link_Group>;
+def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[CC1Option, HelpHidden]>;
+def O4 : Flag<["-"], "O4">, Group<O_Group>, Flags<[CC1Option, HelpHidden]>;
def ObjCXX : Flag<["-"], "ObjC++">, Flags<[DriverOption]>,
HelpText<"Treat source input files as Objective-C++ inputs">;
def ObjC : Flag<["-"], "ObjC">, Flags<[DriverOption]>,
@@ -286,12 +380,12 @@ def ObjC : Flag<["-"], "ObjC">, Flags<[DriverOption]>,
def O : Joined<["-"], "O">, Group<O_Group>, Flags<[CC1Option]>;
def O_flag : Flag<["-"], "O">, Flags<[CC1Option]>, Alias<O>, AliasArgs<["2"]>;
def Ofast : Joined<["-"], "Ofast">, Group<O_Group>, Flags<[CC1Option]>;
-def P : Flag<["-"], "P">, Flags<[CC1Option]>,
+def P : Flag<["-"], "P">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
HelpText<"Disable linemarker output in -E mode">;
-def Qn : Flag<["-"], "Qn">;
+def Qn : Flag<["-"], "Qn">, IgnoredGCCCompat;
def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption, CoreOption]>,
HelpText<"Don't emit warning for unused driver arguments">;
-def Q : Flag<["-"], "Q">;
+def Q : Flag<["-"], "Q">, IgnoredGCCCompat;
def Rpass_EQ : Joined<["-"], "Rpass=">, Group<R_value_Group>, Flags<[CC1Option]>,
HelpText<"Report transformations performed by optimization passes whose "
"name matches the given POSIX regular expression">;
@@ -307,23 +401,28 @@ def R_Joined : Joined<["-"], "R">, Group<R_Group>, Flags<[CC1Option, CoreOption]
MetaVarName<"<remark>">, HelpText<"Enable the specified remark">;
def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
HelpText<"Only run preprocess and compilation steps">;
-def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>;
-def Tdata : JoinedOrSeparate<["-"], "Tdata">, Group<T_Group>;
-def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>;
-def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>;
-def U : JoinedOrSeparate<["-"], "U">, Group<CompileOnly_Group>, Flags<[CC1Option]>;
+def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>,
+ MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">;
+def Tdata : JoinedOrSeparate<["-"], "Tdata">, Group<T_Group>,
+ MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">;
+def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>,
+ MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">;
+def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>,
+ MetaVarName<"<script>">, HelpText<"Specify <script> as linker script">;
+def U : JoinedOrSeparate<["-"], "U">, Group<Preprocessor_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<macro>">, HelpText<"Undefine macro <macro>">;
def V : JoinedOrSeparate<["-"], "V">, Flags<[DriverOption, Unsupported]>;
def Wa_COMMA : CommaJoined<["-"], "Wa,">,
HelpText<"Pass the comma separated arguments in <arg> to the assembler">,
MetaVarName<"<arg>">;
-def Wall : Flag<["-"], "Wall">, Group<W_Group>, Flags<[CC1Option]>;
-def WCL4 : Flag<["-"], "WCL4">, Group<W_Group>, Flags<[CC1Option]>;
-def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>, Flags<[CC1Option]>;
+def Wall : Flag<["-"], "Wall">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>;
+def WCL4 : Flag<["-"], "WCL4">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>;
+def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable warnings for deprecated constructs and define __DEPRECATED">;
def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group<W_Group>, Flags<[CC1Option]>;
-def Wextra : Flag<["-"], "Wextra">, Group<W_Group>, Flags<[CC1Option]>;
def Wl_COMMA : CommaJoined<["-"], "Wl,">, Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass the comma separated arguments in <arg> to the linker">,
- MetaVarName<"<arg>">;
+ MetaVarName<"<arg>">, Group<Link_Group>;
// FIXME: This is broken; these should not be Joined arguments.
def Wno_nonportable_cfstrings : Joined<["-"], "Wno-nonportable-cfstrings">, Group<W_Group>,
Flags<[CC1Option]>;
@@ -331,16 +430,18 @@ def Wnonportable_cfstrings : Joined<["-"], "Wnonportable-cfstrings">, Group<W_Gr
Flags<[CC1Option]>;
def Wp_COMMA : CommaJoined<["-"], "Wp,">,
HelpText<"Pass the comma separated arguments in <arg> to the preprocessor">,
- MetaVarName<"<arg>">;
-def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group<W_Group>, Flags<[CC1Option]>;
-def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group<W_Group>, Flags<[CC1Option]>;
+ MetaVarName<"<arg>">, Group<Preprocessor_Group>;
+def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>;
+def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>;
def W_Joined : Joined<["-"], "W">, Group<W_Group>, Flags<[CC1Option, CoreOption]>,
MetaVarName<"<warning>">, HelpText<"Enable the specified warning">;
def Xanalyzer : Separate<["-"], "Xanalyzer">,
- HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">;
+ HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">,
+ Group<StaticAnalyzer_Group>;
def Xarch__ : JoinedAndSeparate<["-"], "Xarch_">, Flags<[DriverOption]>;
def Xassembler : Separate<["-"], "Xassembler">,
- HelpText<"Pass <arg> to the assembler">, MetaVarName<"<arg>">;
+ HelpText<"Pass <arg> to the assembler">, MetaVarName<"<arg>">,
+ Group<CompileOnly_Group>;
def Xclang : Separate<["-"], "Xclang">,
HelpText<"Pass <arg> to the clang compiler">, MetaVarName<"<arg>">,
Flags<[DriverOption, CoreOption]>, Group<CompileOnly_Group>;
@@ -349,14 +450,17 @@ def Xcuda_fatbinary : Separate<["-"], "Xcuda-fatbinary">,
def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">,
HelpText<"Pass <arg> to the ptxas assembler">, MetaVarName<"<arg>">;
def z : Separate<["-"], "z">, Flags<[LinkerInput, RenderAsInput]>,
- HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">;
+ HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">,
+ Group<Link_Group>;
def Xlinker : Separate<["-"], "Xlinker">, Flags<[LinkerInput, RenderAsInput]>,
- HelpText<"Pass <arg> to the linker">, MetaVarName<"<arg>">;
-def Xpreprocessor : Separate<["-"], "Xpreprocessor">,
+ HelpText<"Pass <arg> to the linker">, MetaVarName<"<arg>">,
+ Group<Link_Group>;
+def Xpreprocessor : Separate<["-"], "Xpreprocessor">, Group<Preprocessor_Group>,
HelpText<"Pass <arg> to the preprocessor">, MetaVarName<"<arg>">;
-def X_Flag : Flag<["-"], "X">;
-def X_Joined : Joined<["-"], "X">;
-def Z_Flag : Flag<["-"], "Z">;
+def X_Flag : Flag<["-"], "X">, Group<Link_Group>;
+def X_Joined : Joined<["-"], "X">, IgnoredGCCCompat;
+def Z_Flag : Flag<["-"], "Z">, Group<Link_Group>;
+// FIXME: All we do with this is reject it. Remove.
def Z_Joined : Joined<["-"], "Z">;
def all__load : Flag<["-"], "all_load">;
def allowable__client : Separate<["-"], "allowable_client">;
@@ -402,7 +506,7 @@ def current__version : JoinedOrSeparate<["-"], "current_version">;
def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>,
HelpText<"Add directory to the C++ SYSTEM include search path">, Flags<[CC1Option]>,
MetaVarName<"<directory>">;
-def c : Flag<["-"], "c">, Flags<[DriverOption]>,
+def c : Flag<["-"], "c">, Flags<[DriverOption]>, Group<Action_Group>,
HelpText<"Only run preprocess, compile, and assemble steps">;
def cuda_device_only : Flag<["--"], "cuda-device-only">,
HelpText<"Compile CUDA code for device only">;
@@ -462,7 +566,7 @@ def emit_ast : Flag<["-"], "emit-ast">,
def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Use the LLVM representation for assembler and object files">;
def exported__symbols__list : Separate<["-"], "exported_symbols_list">;
-def e : JoinedOrSeparate<["-"], "e">;
+def e : JoinedOrSeparate<["-"], "e">, Group<Link_Group>;
def fPIC : Flag<["-"], "fPIC">, Group<f_Group>;
def fno_PIC : Flag<["-"], "fno-PIC">, Group<f_Group>;
def fPIE : Flag<["-"], "fPIE">, Group<f_Group>;
@@ -511,14 +615,28 @@ def fno_gnu_inline_asm : Flag<["-"], "fno-gnu-inline-asm">, Group<f_Group>,
Flags<[DriverOption, CC1Option]>,
HelpText<"Disable GNU style inline asm">;
+def fprofile_sample_use : Flag<["-"], "fprofile-sample-use">, Group<f_Group>,
+ Flags<[CoreOption]>;
+def fno_profile_sample_use : Flag<["-"], "fno-profile-sample-use">, Group<f_Group>,
+ Flags<[CoreOption]>;
def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">,
Group<f_Group>, Flags<[DriverOption, CC1Option]>,
HelpText<"Enable sample-based profile guided optimizations">;
+def fauto_profile : Flag<["-"], "fauto-profile">, Group<f_Group>,
+ Alias<fprofile_sample_use>;
+def fno_auto_profile : Flag<["-"], "fno-auto-profile">, Group<f_Group>,
+ Alias<fno_profile_sample_use>;
def fauto_profile_EQ : Joined<["-"], "fauto-profile=">,
Alias<fprofile_sample_use_EQ>;
+def fdebug_info_for_profiling : Flag<["-"], "fdebug-info-for-profiling">, Group<f_Group>,
+ Flags<[CC1Option]>,
+ HelpText<"Emit extra debug info to make sample profile more accurate.">;
+def fno_debug_info_for_profiling : Flag<["-"], "fno-debug-info-for-profiling">, Group<f_Group>,
+ Flags<[DriverOption]>,
+ HelpText<"Do not emit extra debug info for sample profiler.">;
def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
Group<f_Group>, Flags<[CoreOption]>,
- HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overriden by '=' form of option or LLVM_PROFILE_FILE env var)">;
+ HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
def fprofile_instr_generate_EQ : Joined<["-"], "fprofile-instr-generate=">,
Group<f_Group>, Flags<[CoreOption]>, MetaVarName<"<file>">,
HelpText<"Generate instrumented code to collect execution counts into <file> (overridden by LLVM_PROFILE_FILE env var)">;
@@ -585,7 +703,8 @@ def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group<f_Group>;
def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>;
def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit=">,
Group<f_Group>;
-def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>;
+def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>,
+ HelpText<"Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash">;
def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>;
def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>,
HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>;
@@ -659,65 +778,71 @@ def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>;
def fjump_tables : Flag<["-"], "fjump-tables">, Group<f_Group>;
def fno_jump_tables : Flag<["-"], "fno-jump-tables">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Do not use jump tables for lowering switches">;
+
+// Begin sanitizer flags. These should all be core options exposed in all driver
+// modes.
+let Flags = [CC1Option, CoreOption] in {
+
def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>, MetaVarName<"<check>">,
+ MetaVarName<"<check>">,
HelpText<"Turn on runtime checks for various forms of undefined "
"or suspicious behavior. See user manual for available checks">;
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
- Flags<[CoreOption]>;
+ Flags<[CoreOption, DriverOption]>;
def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">,
- Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>,
+ Group<f_clang_Group>,
HelpText<"Path to blacklist file for sanitizers">;
def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">,
Group<f_clang_Group>,
HelpText<"Don't use blacklist file for sanitizers">;
def fsanitize_coverage
: CommaJoined<["-"], "fsanitize-coverage=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>,
HelpText<"Specify the type of coverage instrumentation for Sanitizers">;
def fno_sanitize_coverage
: CommaJoined<["-"], "fno-sanitize-coverage=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>,
HelpText<"Disable specified features of coverage instrumentation for "
"Sanitizers">;
def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable origins tracking in MemorySanitizer">;
def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable origins tracking in MemorySanitizer">;
def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable origins tracking in MemorySanitizer">;
def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dtor">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable use-after-destroy detection in MemorySanitizer">;
def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Level of field padding for AddressSanitizer">;
def fsanitize_address_use_after_scope : Flag<["-"], "fsanitize-address-use-after-scope">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable use-after-scope detection in AddressSanitizer">;
def fno_sanitize_address_use_after_scope : Flag<["-"], "fno-sanitize-address-use-after-scope">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable use-after-scope detection in AddressSanitizer">;
-def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>,
- Flags<[CoreOption]>;
+def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>;
def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">,
- Group<f_clang_Group>, Flags<[CoreOption]>;
+ Flags<[CoreOption, DriverOption]>,
+ Group<f_clang_Group>;
def fsanitize_recover_EQ : CommaJoined<["-"], "fsanitize-recover=">,
Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>,
HelpText<"Enable recovery for specified sanitizers">;
def fno_sanitize_recover_EQ
: CommaJoined<["-"], "fno-sanitize-recover=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable recovery for specified sanitizers">;
def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>,
HelpText<"Enable trapping for specified sanitizers">;
def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
- Flags<[CoreOption]>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable trapping for specified sanitizers">;
def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">,
Group<f_clang_Group>;
@@ -726,39 +851,47 @@ def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-t
def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">,
Group<f_clang_Group>;
def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable control flow integrity (CFI) checks for cross-DSO calls.">;
def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Flags<[CoreOption, DriverOption]>,
+ Group<f_clang_Group>,
HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">;
def fsanitize_stats : Flag<["-"], "fsanitize-stats">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable sanitizer statistics gathering.">;
def fno_sanitize_stats : Flag<["-"], "fno-sanitize-stats">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable sanitizer statistics gathering.">;
def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">,
Group<f_clang_Group>,
HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">;
def fno_sanitize_thread_memory_access : Flag<["-"], "fno-sanitize-thread-memory-access">,
Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable memory access instrumentation in ThreadSanitizer">;
def fsanitize_thread_func_entry_exit : Flag<["-"], "fsanitize-thread-func-entry-exit">,
Group<f_clang_Group>,
HelpText<"Enable function entry/exit instrumentation in ThreadSanitizer (default)">;
def fno_sanitize_thread_func_entry_exit : Flag<["-"], "fno-sanitize-thread-func-entry-exit">,
Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable function entry/exit instrumentation in ThreadSanitizer">;
def fsanitize_thread_atomics : Flag<["-"], "fsanitize-thread-atomics">,
Group<f_clang_Group>,
HelpText<"Enable atomic operations instrumentation in ThreadSanitizer (default)">;
def fno_sanitize_thread_atomics : Flag<["-"], "fno-sanitize-thread-atomics">,
Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable atomic operations instrumentation in ThreadSanitizer">;
def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-undefined-strip-path-components=">,
- Group<f_clang_Group>, Flags<[CC1Option]>, MetaVarName<"<number>">,
+ Group<f_clang_Group>, MetaVarName<"<number>">,
HelpText<"Strip (or keep only, if negative) a given number of path components "
"when emitting check metadata.">;
+
+} // end -f[no-]sanitize* flags
+
def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
Group<f_Group>;
def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,
@@ -816,12 +949,13 @@ def fno_gnu89_inline : Flag<["-"], "fno-gnu89-inline">, Group<f_Group>;
def fgnu_runtime : Flag<["-"], "fgnu-runtime">, Group<f_Group>,
HelpText<"Generate output compatible with the standard GNU Objective-C runtime">;
def fheinous_gnu_extensions : Flag<["-"], "fheinous-gnu-extensions">, Flags<[CC1Option]>;
-def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>;
+def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>,
+ Group<Link_Group>;
def : Flag<["-"], "findirect-virtual-calls">, Alias<fapple_kext>;
def finline_functions : Flag<["-"], "finline-functions">, Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Inline suitable functions">;
def finline_hint_functions: Flag<["-"], "finline-hint-functions">, Group<f_clang_Group>, Flags<[CC1Option]>,
- HelpText<"Inline functions wich are (explicitly or implicitly) marked inline">;
+ HelpText<"Inline functions which are (explicitly or implicitly) marked inline">;
def finline : Flag<["-"], "finline">, Group<clang_ignored_f_Group>;
def fexperimental_new_pass_manager : Flag<["-"], "fexperimental-new-pass-manager">,
Group<f_clang_Group>, Flags<[CC1Option]>,
@@ -845,10 +979,19 @@ def fxray_instruction_threshold_ :
JoinedOrSeparate<["-"], "fxray-instruction-threshold">,
Group<f_Group>, Flags<[CC1Option]>;
+def fxray_always_instrument :
+ JoinedOrSeparate<["-"], "fxray-always-instrument=">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Filename defining the whitelist for imbuing the 'always instrument' XRay attribute.">;
+def fxray_never_instrument :
+ JoinedOrSeparate<["-"], "fxray-never-instrument=">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.">;
+
def flat__namespace : Flag<["-"], "flat_namespace">;
def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
-def flto_EQ : Joined<["-"], "flto=">, Flags<[CC1Option]>, Group<f_Group>,
+def flto_EQ : Joined<["-"], "flto=">, Flags<[CoreOption, CC1Option]>, Group<f_Group>,
HelpText<"Set LTO mode to either 'full' or 'thin'">;
def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group<f_Group>,
HelpText<"Enable LTO in 'full' mode">;
@@ -1213,6 +1356,10 @@ def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>,
HelpText<"Limit debug information produced to reduce size of debug binary">;
def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Flags<[CoreOption]>, Alias<fno_standalone_debug>;
def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Flags<[CoreOption]>, Alias<fstandalone_debug>;
+def fdebug_macro : Flag<["-"], "fdebug-macro">, Group<f_Group>, Flags<[CoreOption]>,
+ HelpText<"Emit macro debug information">;
+def fno_debug_macro : Flag<["-"], "fno-debug-macro">, Group<f_Group>, Flags<[CoreOption]>,
+ HelpText<"Do not emit macro debug information">;
def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>,
Flags<[DriverOption, CoreOption]>;
def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>,
@@ -1335,8 +1482,8 @@ def fno_unique_section_names : Flag <["-"], "fno-unique-section-names">,
def fstrict_return : Flag<["-"], "fstrict-return">, Group<f_Group>,
Flags<[CC1Option]>,
- HelpText<"Always treat control flow paths that fall off the end of a non-void"
- "function as unreachable">;
+ HelpText<"Always treat control flow paths that fall off the end of a "
+ "non-void function as unreachable">;
def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>,
Flags<[CC1Option]>;
@@ -1411,6 +1558,11 @@ def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group<clang_i_Group>, Flag
HelpText<"Add directory to AFTER include search path">;
def iframework : JoinedOrSeparate<["-"], "iframework">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Add directory to SYSTEM framework search path">;
+def iframeworkwithsysroot : JoinedOrSeparate<["-"], "iframeworkwithsysroot">,
+ Group<clang_i_Group>,
+ HelpText<"Add directory to SYSTEM framework search path, "
+ "absolute paths are relative to -isysroot">,
+ MetaVarName<"<directory>">, Flags<[CC1Option]>;
def imacros : JoinedOrSeparate<["-", "--"], "imacros">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Include macros from file before parsing">, MetaVarName<"<file>">;
def image__base : Separate<["-"], "image_base">;
@@ -1449,7 +1601,8 @@ def ivfsoverlay : JoinedOrSeparate<["-"], "ivfsoverlay">, Group<clang_i_Group>,
HelpText<"Overlay the virtual filesystem described by file over the real file system">;
def i : Joined<["-"], "i">, Group<i_Group>;
def keep__private__externs : Flag<["-"], "keep_private_externs">;
-def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>;
+def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>,
+ Group<Link_Group>;
def lazy__framework : Separate<["-"], "lazy_framework">, Flags<[LinkerInput]>;
def lazy__library : Separate<["-"], "lazy_library">, Flags<[LinkerInput]>;
def mlittle_endian : Flag<["-"], "mlittle-endian">, Flags<[DriverOption]>;
@@ -1484,11 +1637,11 @@ def mpure_code : Flag<["-"], "mpure-code">, Alias<mexecute_only>; // Alias for G
def mno_pure_code : Flag<["-"], "mno-pure-code">, Alias<mno_execute_only>;
def mtvos_version_min_EQ : Joined<["-"], "mtvos-version-min=">, Group<m_Group>;
def mappletvos_version_min_EQ : Joined<["-"], "mappletvos-version-min=">, Alias<mtvos_version_min_EQ>;
-def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">, Alias<mtvos_version_min_EQ>;
-def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_version_min_EQ>;
+def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">;
+def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_simulator_version_min_EQ>;
def mwatchos_version_min_EQ : Joined<["-"], "mwatchos-version-min=">, Group<m_Group>;
-def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">, Alias<mwatchos_version_min_EQ>;
-def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_version_min_EQ>;
+def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">;
+def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_simulator_version_min_EQ>;
def march_EQ : Joined<["-"], "march=">, Group<m_Group>;
def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>;
def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>;
@@ -1517,8 +1670,8 @@ def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>;
def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>;
def mios_version_min_EQ : Joined<["-"], "mios-version-min=">,
Alias<miphoneos_version_min_EQ>, HelpText<"Set iOS deployment target">;
-def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">, Alias<miphoneos_version_min_EQ>;
-def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<miphoneos_version_min_EQ>;
+def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">;
+def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<mios_simulator_version_min_EQ>;
def mkernel : Flag<["-"], "mkernel">, Group<m_Group>;
def mlinker_version_EQ : Joined<["-"], "mlinker-version=">,
Flags<[DriverOption]>;
@@ -1604,7 +1757,14 @@ def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>;
def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>;
def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>;
def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group<m_x86_Features_Group>;
+def mno_clzero : Flag<["-"], "mno-clzero">, Group<m_x86_Features_Group>;
def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>;
+def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group<m_x86_Features_Group>;
+def mno_clwb : Flag<["-"], "mno-clwb">, Group<m_x86_Features_Group>;
+def mno_movbe : Flag<["-"], "mno-movbe">, Group<m_x86_Features_Group>;
+def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>;
+def mno_sgx : Flag<["-"], "mno-sgx">, Group<m_x86_Features_Group>;
+def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group<m_x86_Features_Group>;
def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">;
@@ -1626,6 +1786,8 @@ def mcrc : Flag<["-"], "mcrc">, Group<m_arm_Features_Group>,
HelpText<"Allow use of CRC instructions (ARM only)">;
def mnocrc : Flag<["-"], "mnocrc">, Group<m_arm_Features_Group>,
HelpText<"Disallow use of CRC instructions (ARM only)">;
+def mno_neg_immediates: Flag<["-"], "mno-neg-immediates">, Group<m_arm_Features_Group>,
+ HelpText<"Disallow converting instructions with negative immediates to their negation or inversion.">;
def mgeneral_regs_only : Flag<["-"], "mgeneral-regs-only">, Group<m_aarch64_Features_Group>,
HelpText<"Generate code which only uses the general purpose registers (AArch64 only)">;
@@ -1648,6 +1810,10 @@ def mamdgpu_debugger_abi : Joined<["-"], "mamdgpu-debugger-abi=">,
HelpText<"Generate additional code for specified <version> of debugger ABI (AMDGPU only)">,
MetaVarName<"<version>">;
+def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[DriverOption]>;
+def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[DriverOption]>;
+def maltivec : Flag<["-"], "maltivec">, Group<m_ppc_Features_Group>;
+def mno_altivec : Flag<["-"], "mno-altivec">, Group<m_ppc_Features_Group>;
def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>;
def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>;
def mpower8_vector : Flag<["-"], "mpower8-vector">,
@@ -1698,12 +1864,6 @@ def mlongcall: Flag<["-"], "mlongcall">,
def mno_longcall : Flag<["-"], "mno-longcall">,
Group<m_ppc_Features_Group>;
-def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Enable AltiVec vector initializer syntax">;
-def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[CC1Option]>;
-def maltivec : Flag<["-"], "maltivec">, Alias<faltivec>;
-def mno_altivec : Flag<["-"], "mno-altivec">, Alias<fno_altivec>;
-
def mvx : Flag<["-"], "mvx">, Group<m_Group>;
def mno_vx : Flag<["-"], "mno-vx">, Group<m_Group>;
@@ -1735,7 +1895,8 @@ def mno_incremental_linker_compatible : Flag<["-"], "mno-incremental-linker-comp
HelpText<"(integrated-as) Emit an object file which cannot be used with an incremental linker">;
def mrtd : Flag<["-"], "mrtd">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Make StdCall calling convention the default">;
-def msmall_data_threshold_EQ : Joined <["-"], "msmall-data-threshold=">, Group<m_Group>;
+def msmall_data_threshold_EQ : Joined <["-"], "msmall-data-threshold=">,
+ Group<m_Group>, Alias<G>;
def msoft_float : Flag<["-"], "msoft-float">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Use software floating point">;
def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>,
@@ -1747,6 +1908,8 @@ def mpie_copy_relocations : Flag<["-"], "mpie-copy-relocations">, Group<m_Group>
Flags<[CC1Option]>,
HelpText<"Use copy relocations support for PIE builds">;
def mno_pie_copy_relocations : Flag<["-"], "mno-pie-copy-relocations">, Group<m_Group>;
+def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86 only)">,
+ Flags<[CC1Option]>, Group<m_Group>;
def mx87 : Flag<["-"], "mx87">, Group<m_x86_Features_Group>;
def m80387 : Flag<["-"], "m80387">, Alias<mx87>;
def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>;
@@ -1794,6 +1957,13 @@ def mxsaveopt : Flag<["-"], "mxsaveopt">, Group<m_x86_Features_Group>;
def mxsavec : Flag<["-"], "mxsavec">, Group<m_x86_Features_Group>;
def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>;
def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>;
+def mclzero : Flag<["-"], "mclzero">, Group<m_x86_Features_Group>;
+def mclflushopt : Flag<["-"], "mclflushopt">, Group<m_x86_Features_Group>;
+def mclwb : Flag<["-"], "mclwb">, Group<m_x86_Features_Group>;
+def mmovbe : Flag<["-"], "mmovbe">, Group<m_x86_Features_Group>;
+def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>;
+def msgx : Flag<["-"], "msgx">, Group<m_x86_Features_Group>;
+def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group<m_x86_Features_Group>;
def mips16 : Flag<["-"], "mips16">, Group<m_Group>;
def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_Group>;
def mmicromips : Flag<["-"], "mmicromips">, Group<m_Group>;
@@ -1938,6 +2108,8 @@ def print_multi_os_directory : Flag<["-", "--"], "print-multi-os-directory">,
Flags<[Unsupported]>;
def print_prog_name_EQ : Joined<["-", "--"], "print-prog-name=">,
HelpText<"Print the full program path of <name>">, MetaVarName<"<name>">;
+def print_resource_dir : Flag<["-", "--"], "print-resource-dir">,
+ HelpText<"Print the resource directory pathname">;
def print_search_dirs : Flag<["-", "--"], "print-search-dirs">,
HelpText<"Print the paths used for finding libraries and programs">;
def private__bundle : Flag<["-"], "private_bundle">;
@@ -1959,10 +2131,15 @@ def resource_dir : Separate<["-"], "resource-dir">,
HelpText<"The directory which holds the compiler resource files">;
def resource_dir_EQ : Joined<["-"], "resource-dir=">, Flags<[DriverOption, CoreOption]>,
Alias<resource_dir>;
-def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>;
+def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>, Group<Link_Group>;
def rtlib_EQ : Joined<["-", "--"], "rtlib=">,
HelpText<"Compiler runtime library to use">;
-def r : Flag<["-"], "r">, Flags<[LinkerInput,NoArgumentUnused]>;
+def frtlib_add_rpath: Flag<["-"], "frtlib-add-rpath">, Flags<[NoArgumentUnused]>,
+ HelpText<"Add -rpath with architecture-specific resource directory to the linker flags">;
+def fno_rtlib_add_rpath: Flag<["-"], "fno-rtlib-add-rpath">, Flags<[NoArgumentUnused]>,
+ HelpText<"Do not add -rpath with architecture-specific resource directory to the linker flags">;
+def r : Flag<["-"], "r">, Flags<[LinkerInput,NoArgumentUnused]>,
+ Group<Link_Group>;
def save_temps_EQ : Joined<["-", "--"], "save-temps=">, Flags<[DriverOption]>,
HelpText<"Save intermediate compilation results.">;
def save_temps : Flag<["-", "--"], "save-temps">, Flags<[DriverOption]>,
@@ -2014,7 +2191,7 @@ def no_system_header_prefix : Joined<["--"], "no-system-header-prefix=">,
HelpText<"Treat all #include paths starting with <prefix> as not including a "
"system header.">;
def : Separate<["--"], "no-system-header-prefix">, Alias<no_system_header_prefix>;
-def s : Flag<["-"], "s">;
+def s : Flag<["-"], "s">, Group<Link_Group>;
def target : Joined<["--"], "target=">, Flags<[DriverOption, CoreOption]>,
HelpText<"Generate code for the given target">;
def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[DriverOption]>,
@@ -2028,7 +2205,7 @@ def trigraphs : Flag<["-", "--"], "trigraphs">, Alias<ftrigraphs>,
HelpText<"Process trigraph sequences">;
def twolevel__namespace__hints : Flag<["-"], "twolevel_namespace_hints">;
def twolevel__namespace : Flag<["-"], "twolevel_namespace">;
-def t : Flag<["-"], "t">;
+def t : Flag<["-"], "t">, Group<Link_Group>;
def umbrella : Separate<["-"], "umbrella">;
def undefined : JoinedOrSeparate<["-"], "undefined">, Group<u_Group>;
def undef : Flag<["-"], "undef">, Group<u_Group>, Flags<[CC1Option]>,
@@ -2185,6 +2362,8 @@ def mv55 : Flag<["-"], "mv55">, Group<m_hexagon_Features_Group>,
Alias<mcpu_EQ>, AliasArgs<["hexagonv55"]>;
def mv60 : Flag<["-"], "mv60">, Group<m_hexagon_Features_Group>,
Alias<mcpu_EQ>, AliasArgs<["hexagonv60"]>;
+def mv62 : Flag<["-"], "mv62">, Group<m_hexagon_Features_Group>,
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv62"]>;
def mhexagon_hvx : Flag<["-"], "mhvx">, Group<m_hexagon_Features_Group>,
Flags<[CC1Option]>, HelpText<"Enable Hexagon Vector eXtensions">;
def mno_hexagon_hvx : Flag<["-"], "mno-hvx">, Group<m_hexagon_Features_Group>,
@@ -2322,10 +2501,6 @@ defm devirtualize : BooleanFFlag<"devirtualize">, Group<clang_ignored_gcc_optimi
defm devirtualize_speculatively : BooleanFFlag<"devirtualize-speculatively">,
Group<clang_ignored_gcc_optimization_f_Group>;
-// gfortran options that we recognize in the driver and pass along when
-// invoking GCC to compile Fortran code.
-def gfortran_Group : OptionGroup<"gfortran Group">;
-
// Generic gfortran options.
def A_DASH : Joined<["-"], "A-">, Group<gfortran_Group>;
def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined]>, Group<gfortran_Group>;
diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h
index 6206680118d5..2df8077d6da6 100644
--- a/include/clang/Driver/SanitizerArgs.h
+++ b/include/clang/Driver/SanitizerArgs.h
@@ -34,7 +34,7 @@ class SanitizerArgs {
bool CfiCrossDso = false;
int AsanFieldPadding = 0;
bool AsanSharedRuntime = false;
- bool AsanUseAfterScope = false;
+ bool AsanUseAfterScope = true;
bool LinkCXXRuntimes = false;
bool NeedPIE = false;
bool Stats = false;
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index 5012cc896683..8f76e17c48ba 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -35,7 +35,7 @@ class Tool {
public:
// Documents the level of support for response files in this tool.
// Response files are necessary if the command line gets too large,
- // requiring the arguments to be transfered to a file.
+ // requiring the arguments to be transferred to a file.
enum ResponseFileSupport {
// Provides full support for response files, which means we can transfer
// all tool input arguments to a file. E.g.: clang, gcc, binutils and MSVC
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index ffb0d60a6398..105d0f338ac6 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -44,6 +44,7 @@ namespace driver {
class RegisterEffectiveTriple;
class SanitizerArgs;
class Tool;
+ class XRayArgs;
/// ToolChain - Access to tools for a single platform.
class ToolChain {
@@ -94,12 +95,15 @@ private:
Tool *getOffloadBundler() const;
mutable std::unique_ptr<SanitizerArgs> SanitizerArguments;
+ mutable std::unique_ptr<XRayArgs> XRayArguments;
/// The effective clang triple for the current Job.
mutable llvm::Triple EffectiveTriple;
/// Set the toolchain's effective clang triple.
- void setEffectiveTriple(llvm::Triple ET) const { EffectiveTriple = ET; }
+ void setEffectiveTriple(llvm::Triple ET) const {
+ EffectiveTriple = std::move(ET);
+ }
friend class RegisterEffectiveTriple;
@@ -175,6 +179,8 @@ public:
const SanitizerArgs& getSanitizerArgs() const;
+ const XRayArgs& getXRayArgs() const;
+
// Returns the Arg * that explicitly turned on/off rtti, or nullptr.
const llvm::opt::Arg *getRTTIArg() const { return CachedRTTIArg; }
@@ -299,6 +305,11 @@ public:
const char *getCompilerRTArgString(const llvm::opt::ArgList &Args,
StringRef Component,
bool Shared = false) const;
+
+ // Returns <ResourceDir>/lib/<OSName>/<arch>. This is used by runtimes (such
+ // as OpenMP) to find arch-specific libraries.
+ std::string getArchSpecificLibPath() const;
+
/// needsProfileRT - returns true if instrumentation profile is on.
static bool needsProfileRT(const llvm::opt::ArgList &Args);
@@ -471,7 +482,7 @@ class RegisterEffectiveTriple {
public:
RegisterEffectiveTriple(const ToolChain &TC, llvm::Triple T) : TC(TC) {
- TC.setEffectiveTriple(T);
+ TC.setEffectiveTriple(std::move(T));
}
~RegisterEffectiveTriple() { TC.setEffectiveTriple(llvm::Triple()); }
diff --git a/include/clang/Driver/XRayArgs.h b/include/clang/Driver/XRayArgs.h
new file mode 100644
index 000000000000..83210d100a12
--- /dev/null
+++ b/include/clang/Driver/XRayArgs.h
@@ -0,0 +1,38 @@
+//===--- XRayArgs.h - Arguments for XRay ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_DRIVER_XRAYARGS_H
+#define LLVM_CLANG_DRIVER_XRAYARGS_H
+
+#include "clang/Driver/Types.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+
+namespace clang {
+namespace driver {
+
+class ToolChain;
+
+class XRayArgs {
+ std::vector<std::string> AlwaysInstrumentFiles;
+ std::vector<std::string> NeverInstrumentFiles;
+ std::vector<std::string> ExtraDeps;
+ bool XRayInstrument = false;
+ int InstructionThreshold = 200;
+
+public:
+ /// Parses the XRay arguments from an argument list.
+ XRayArgs(const ToolChain &TC, const llvm::opt::ArgList &Args);
+ void addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const;
+};
+
+} // namespace driver
+} // namespace clang
+
+#endif // LLVM_CLANG_DRIVER_XRAYARGS_H
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 6c6458b33d85..05daf4f897f4 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -100,6 +100,19 @@ struct FormatStyle {
/// \brief If ``true``, aligns escaped newlines as far left as possible.
/// Otherwise puts them into the right-most column.
+ /// \code
+ /// true:
+ /// #define A \
+ /// int aaaa; \
+ /// int b; \
+ /// int dddddddddd;
+ ///
+ /// false:
+ /// #define A \
+ /// int aaaa; \
+ /// int b; \
+ /// int dddddddddd;
+ /// \endcode
bool AlignEscapedNewlinesLeft;
/// \brief If ``true``, horizontally align operands of binary and ternary
@@ -114,10 +127,21 @@ struct FormatStyle {
bool AlignOperands;
/// \brief If ``true``, aligns trailing comments.
+ /// \code
+ /// true: false:
+ /// int a; // My comment a vs. int a; // My comment a
+ /// int b = 2; // comment b int b = 2; // comment about b
+ /// \endcode
bool AlignTrailingComments;
/// \brief Allow putting all parameters of a function declaration onto
/// the next line even if ``BinPackParameters`` is ``false``.
+ /// \code
+ /// true: false:
+ /// myFunction(foo, vs. myFunction(foo, bar, plop);
+ /// bar,
+ /// plop);
+ /// \endcode
bool AllowAllParametersOfDeclarationOnNextLine;
/// \brief Allows contracting simple braced statements to a single line.
@@ -126,6 +150,16 @@ struct FormatStyle {
bool AllowShortBlocksOnASingleLine;
/// \brief If ``true``, short case labels will be contracted to a single line.
+ /// \code
+ /// true: false:
+ /// switch (a) { vs. switch (a) {
+ /// case 1: x = 1; break; case 1:
+ /// case 2: return; x = 1;
+ /// } break;
+ /// case 2:
+ /// return;
+ /// }
+ /// \endcode
bool AllowShortCaseLabelsOnASingleLine;
/// \brief Different styles for merging short functions containing at most one
@@ -134,10 +168,27 @@ struct FormatStyle {
/// \brief Never merge functions into a single line.
SFS_None,
/// \brief Only merge empty functions.
+ /// \code
+ /// void f() { bar(); }
+ /// void f2() {
+ /// bar2();
+ /// }
+ /// \endcode
SFS_Empty,
/// \brief Only merge functions defined inside a class. Implies "empty".
+ /// \code
+ /// class Foo {
+ /// void f() { foo(); }
+ /// };
+ /// \endcode
SFS_Inline,
/// \brief Merge all functions fitting on a single line.
+ /// \code
+ /// class Foo {
+ /// void f() { foo(); }
+ /// };
+ /// void f() { bar(); }
+ /// \endcode
SFS_All,
};
@@ -153,6 +204,7 @@ struct FormatStyle {
bool AllowShortLoopsOnASingleLine;
/// \brief Different ways to break after the function definition return type.
+ /// This option is **deprecated** and is retained for backwards compatibility.
enum DefinitionReturnTypeBreakingStyle {
/// Break after return type automatically.
/// ``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
@@ -168,19 +220,74 @@ struct FormatStyle {
enum ReturnTypeBreakingStyle {
/// Break after return type automatically.
/// ``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
+ /// \code
+ /// class A {
+ /// int f() { return 0; };
+ /// };
+ /// int f();
+ /// int f() { return 1; }
+ /// \endcode
RTBS_None,
/// Always break after the return type.
+ /// \code
+ /// class A {
+ /// int
+ /// f() {
+ /// return 0;
+ /// };
+ /// };
+ /// int
+ /// f();
+ /// int
+ /// f() {
+ /// return 1;
+ /// }
+ /// \endcode
RTBS_All,
/// Always break after the return types of top-level functions.
+ /// \code
+ /// class A {
+ /// int f() { return 0; };
+ /// };
+ /// int
+ /// f();
+ /// int
+ /// f() {
+ /// return 1;
+ /// }
+ /// \endcode
RTBS_TopLevel,
/// Always break after the return type of function definitions.
+ /// \code
+ /// class A {
+ /// int
+ /// f() {
+ /// return 0;
+ /// };
+ /// };
+ /// int f();
+ /// int
+ /// f() {
+ /// return 1;
+ /// }
+ /// \endcode
RTBS_AllDefinitions,
/// Always break after the return type of top-level definitions.
+ /// \code
+ /// class A {
+ /// int f() { return 0; };
+ /// };
+ /// int f();
+ /// int
+ /// f() {
+ /// return 1;
+ /// }
+ /// \endcode
RTBS_TopLevelDefinitions,
};
/// \brief The function definition return type breaking style to use. This
- /// option is deprecated and is retained for backwards compatibility.
+ /// option is **deprecated** and is retained for backwards compatibility.
DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType;
/// \brief The function declaration return type breaking style to use.
@@ -192,27 +299,92 @@ struct FormatStyle {
/// in a file look more consistent. Thus, it will only take effect if wrapping
/// the string at that point leads to it being indented
/// ``ContinuationIndentWidth`` spaces from the start of the line.
+ /// \code
+ /// true: false:
+ /// aaaa = vs. aaaa = "bbbb"
+ /// "bbbb" "cccc";
+ /// "cccc";
+ /// \endcode
bool AlwaysBreakBeforeMultilineStrings;
/// \brief If ``true``, always break after the ``template<...>`` of a template
/// declaration.
+ /// \code
+ /// true: false:
+ /// template <typename T> vs. template <typename T> class C {};
+ /// class C {};
+ /// \endcode
bool AlwaysBreakTemplateDeclarations;
/// \brief If ``false``, a function call's arguments will either be all on the
/// same line or will have one line each.
+ /// \code
+ /// true:
+ /// void f() {
+ /// f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa,
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
+ /// }
+ ///
+ /// false:
+ /// void f() {
+ /// f(aaaaaaaaaaaaaaaaaaaa,
+ /// aaaaaaaaaaaaaaaaaaaa,
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
+ /// }
+ /// \endcode
bool BinPackArguments;
/// \brief If ``false``, a function declaration's or function definition's
/// parameters will either all be on the same line or will have one line each.
+ /// \code
+ /// true:
+ /// void f(int aaaaaaaaaaaaaaaaaaaa, int aaaaaaaaaaaaaaaaaaaa,
+ /// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
+ ///
+ /// false:
+ /// void f(int aaaaaaaaaaaaaaaaaaaa,
+ /// int aaaaaaaaaaaaaaaaaaaa,
+ /// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
+ /// \endcode
bool BinPackParameters;
/// \brief The style of breaking before or after binary operators.
enum BinaryOperatorStyle {
/// Break after operators.
+ /// \code
+ /// LooooooooooongType loooooooooooooooooooooongVariable =
+ /// someLooooooooooooooooongFunction();
+ ///
+ /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >
+ /// ccccccccccccccccccccccccccccccccccccccccc;
+ /// \endcode
BOS_None,
/// Break before operators that aren't assignments.
+ /// \code
+ /// LooooooooooongType loooooooooooooooooooooongVariable =
+ /// someLooooooooooooooooongFunction();
+ ///
+ /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// > ccccccccccccccccccccccccccccccccccccccccc;
+ /// \endcode
BOS_NonAssignment,
/// Break before operators.
+ /// \code
+ /// LooooooooooongType loooooooooooooooooooooongVariable
+ /// = someLooooooooooooooooongFunction();
+ ///
+ /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// > ccccccccccccccccccccccccccccccccccccccccc;
+ /// \endcode
BOS_All,
};
@@ -222,23 +394,133 @@ struct FormatStyle {
/// \brief Different ways to attach braces to their surrounding context.
enum BraceBreakingStyle {
/// Always attach braces to surrounding context.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo {};
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_Attach,
/// Like ``Attach``, but break before braces on function, namespace and
/// class definitions.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_Linux,
/// Like ``Attach``, but break before braces on enum, function, and record
/// definitions.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_Mozilla,
/// Like ``Attach``, but break before function definitions, ``catch``, and
/// ``else``.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int
+ /// {
+ /// A,
+ /// B
+ /// };
+ /// \endcode
BS_Stroustrup,
/// Always break before braces.
+ /// \code
+ /// try {
+ /// foo();
+ /// }
+ /// catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo {
+ /// };
+ /// if (foo()) {
+ /// }
+ /// else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_Allman,
/// Always break before braces and add an extra level of indentation to
/// braces of control statements, not to those of class, function
/// or other definitions.
+ /// \code
+ /// try
+ /// {
+ /// foo();
+ /// }
+ /// catch ()
+ /// {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo())
+ /// {
+ /// }
+ /// else
+ /// {
+ /// }
+ /// enum X : int
+ /// {
+ /// A,
+ /// B
+ /// };
+ /// \endcode
BS_GNU,
/// Like ``Attach``, but break before functions.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo {
+ /// };
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_WebKit,
/// Configure each individual brace in `BraceWrapping`.
BS_Custom
@@ -248,26 +530,144 @@ struct FormatStyle {
BraceBreakingStyle BreakBeforeBraces;
/// \brief Precise control over the wrapping of braces.
+ /// \code
+ /// # Should be declared this way:
+ /// BreakBeforeBraces: Custom
+ /// BraceWrapping:
+ /// AfterClass: true
+ /// \endcode
struct BraceWrappingFlags {
/// \brief Wrap class definitions.
+ /// \code
+ /// true:
+ /// class foo {};
+ ///
+ /// false:
+ /// class foo
+ /// {};
+ /// \endcode
bool AfterClass;
/// \brief Wrap control statements (``if``/``for``/``while``/``switch``/..).
+ /// \code
+ /// true:
+ /// if (foo())
+ /// {
+ /// } else
+ /// {}
+ /// for (int i = 0; i < 10; ++i)
+ /// {}
+ ///
+ /// false:
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// for (int i = 0; i < 10; ++i) {
+ /// }
+ /// \endcode
bool AfterControlStatement;
/// \brief Wrap enum definitions.
+ /// \code
+ /// true:
+ /// enum X : int
+ /// {
+ /// B
+ /// };
+ ///
+ /// false:
+ /// enum X : int { B };
+ /// \endcode
bool AfterEnum;
/// \brief Wrap function definitions.
+ /// \code
+ /// true:
+ /// void foo()
+ /// {
+ /// bar();
+ /// bar2();
+ /// }
+ ///
+ /// false:
+ /// void foo() {
+ /// bar();
+ /// bar2();
+ /// }
+ /// \endcode
bool AfterFunction;
/// \brief Wrap namespace definitions.
+ /// \code
+ /// true:
+ /// namespace
+ /// {
+ /// int foo();
+ /// int bar();
+ /// }
+ ///
+ /// false:
+ /// namespace {
+ /// int foo();
+ /// int bar();
+ /// }
+ /// \endcode
bool AfterNamespace;
/// \brief Wrap ObjC definitions (``@autoreleasepool``, interfaces, ..).
bool AfterObjCDeclaration;
/// \brief Wrap struct definitions.
+ /// \code
+ /// true:
+ /// struct foo
+ /// {
+ /// int x;
+ /// }
+ ///
+ /// false:
+ /// struct foo {
+ /// int x;
+ /// }
+ /// \endcode
bool AfterStruct;
/// \brief Wrap union definitions.
+ /// \code
+ /// true:
+ /// union foo
+ /// {
+ /// int x;
+ /// }
+ ///
+ /// false:
+ /// union foo {
+ /// int x;
+ /// }
+ /// \endcode
bool AfterUnion;
/// \brief Wrap before ``catch``.
+ /// \code
+ /// true:
+ /// try {
+ /// foo();
+ /// }
+ /// catch () {
+ /// }
+ ///
+ /// false:
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// \endcode
bool BeforeCatch;
/// \brief Wrap before ``else``.
+ /// \code
+ /// true:
+ /// if (foo()) {
+ /// }
+ /// else {
+ /// }
+ ///
+ /// false:
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// \endcode
bool BeforeElse;
/// \brief Indent the wrapped braces themselves.
bool IndentBraces;
@@ -280,13 +680,37 @@ struct FormatStyle {
BraceWrappingFlags BraceWrapping;
/// \brief If ``true``, ternary operators will be placed after line breaks.
+ /// \code
+ /// true:
+ /// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription
+ /// ? firstValue
+ /// : SecondValueVeryVeryVeryVeryLong;
+ ///
+ /// true:
+ /// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ?
+ /// firstValue :
+ /// SecondValueVeryVeryVeryVeryLong;
+ /// \endcode
bool BreakBeforeTernaryOperators;
/// \brief Always break constructor initializers before commas and align
/// the commas with the colon.
+ /// \code
+ /// true: false:
+ /// SomeClass::Constructor() vs. SomeClass::Constructor() : a(a),
+ /// : a(a) b(b),
+ /// , b(b) c(c) {}
+ /// , c(c) {}
+ /// \endcode
bool BreakConstructorInitializersBeforeComma;
/// \brief Break after each annotation on a field in Java files.
+ /// \code{.java}
+ /// true: false:
+ /// @Partial vs. @Partial @Mock DataLoad loader;
+ /// @Mock
+ /// DataLoad loader;
+ /// \endcode
bool BreakAfterJavaFieldAnnotations;
/// \brief Allow breaking string literals when formatting.
@@ -301,10 +725,40 @@ struct FormatStyle {
/// \brief A regular expression that describes comments with special meaning,
/// which should not be split into lines or otherwise changed.
+ /// \code
+ /// // CommentPragmas: '^ FOOBAR pragma:'
+ /// // Will leave the following line unaffected
+ /// #include <vector> // FOOBAR pragma: keep
+ /// \endcode
std::string CommentPragmas;
+ /// \brief If ``true``, in the class inheritance expression clang-format will
+ /// break before ``:`` and ``,`` if there is multiple inheritance.
+ /// \code
+ /// true: false:
+ /// class MyClass vs. class MyClass : public X, public Y {
+ /// : public X };
+ /// , public Y {
+ /// };
+ /// \endcode
+ bool BreakBeforeInheritanceComma;
+
/// \brief If the constructor initializers don't fit on a line, put each
/// initializer on its own line.
+ /// \code
+ /// true:
+ /// SomeClass::Constructor()
+ /// : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) {
+ /// return 0;
+ /// }
+ ///
+ /// false:
+ /// SomeClass::Constructor()
+ /// : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa),
+ /// aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) {
+ /// return 0;
+ /// }
+ /// \endcode
bool ConstructorInitializerAllOnOneLineOrOnePerLine;
/// \brief The number of characters to use for indentation of constructor
@@ -312,6 +766,13 @@ struct FormatStyle {
unsigned ConstructorInitializerIndentWidth;
/// \brief Indent width for line continuations.
+ /// \code
+ /// ContinuationIndentWidth: 2
+ ///
+ /// int i = // VeryVeryVeryVeryVeryLongComment
+ /// longFunction( // Again a long comment
+ /// arg);
+ /// \endcode
unsigned ContinuationIndentWidth;
/// \brief If ``true``, format braced lists as best suited for C++11 braced
@@ -327,11 +788,20 @@ struct FormatStyle {
/// (e.g. a type or variable name), clang-format formats as if the ``{}`` were
/// the parentheses of a function call with that name. If there is no name,
/// a zero-length name is assumed.
+ /// \code
+ /// true: false:
+ /// vector<int> x{1, 2, 3, 4}; vs. vector<int> x{ 1, 2, 3, 4 };
+ /// vector<T> x{{}, {}, {}, {}}; vector<T> x{ {}, {}, {}, {} };
+ /// f(MyMap[{composite, key}]); f(MyMap[{ composite, key }]);
+ /// new int[3]{1, 2, 3}; new int[3]{ 1, 2, 3 };
+ /// \endcode
bool Cpp11BracedListStyle;
/// \brief If ``true``, analyze the formatted file for the most common
- /// alignment of ``&`` and ``*``. ``PointerAlignment`` is then used only as
- /// fallback.
+ /// alignment of ``&`` and ``*``.
+ /// Pointer and reference alignment styles are going to be updated according
+ /// to the preferences found in the file.
+ /// ``PointerAlignment`` is then used only as fallback.
bool DerivePointerAlignment;
/// \brief Disables formatting completely.
@@ -349,6 +819,16 @@ struct FormatStyle {
/// not use this in config files, etc. Use at your own risk.
bool ExperimentalAutoDetectBinPacking;
+ /// \brief If ``true``, clang-format adds missing namespace end comments and
+ /// fixes invalid existing ones.
+ /// \code
+ /// true: false:
+ /// namespace a { vs. namespace a {
+ /// foo(); foo();
+ /// } // namespace a; }
+ /// \endcode
+ bool FixNamespaceComments;
+
/// \brief A vector of macros that should be interpreted as foreach loops
/// instead of as function calls.
///
@@ -422,23 +902,64 @@ struct FormatStyle {
///
/// When ``false``, use the same indentation level as for the switch statement.
/// Switch statement body is always indented one level more than case labels.
+ /// \code
+ /// false: true:
+ /// switch (fool) { vs. switch (fool) {
+ /// case 1: case 1:
+ /// bar(); bar();
+ /// break; break;
+ /// default: default:
+ /// plop(); plop();
+ /// } }
+ /// \endcode
bool IndentCaseLabels;
/// \brief The number of columns to use for indentation.
+ /// \code
+ /// IndentWidth: 3
+ ///
+ /// void f() {
+ /// someFunction();
+ /// if (true, false) {
+ /// f();
+ /// }
+ /// }
+ /// \endcode
unsigned IndentWidth;
/// \brief Indent if a function definition or declaration is wrapped after the
/// type.
+ /// \code
+ /// true:
+ /// LoooooooooooooooooooooooooooooooooooooooongReturnType
+ /// LoooooooooooooooooooooooooooooooongFunctionDeclaration();
+ ///
+ /// false:
+ /// LoooooooooooooooooooooooooooooooooooooooongReturnType
+ /// LoooooooooooooooooooooooooooooooongFunctionDeclaration();
+ /// \endcode
bool IndentWrappedFunctionNames;
/// \brief Quotation styles for JavaScript strings. Does not affect template
/// strings.
enum JavaScriptQuoteStyle {
/// Leave string quotes as they are.
+ /// \code{.js}
+ /// string1 = "foo";
+ /// string2 = 'bar';
+ /// \endcode
JSQS_Leave,
/// Always use single quotes.
+ /// \code{.js}
+ /// string1 = 'foo';
+ /// string2 = 'bar';
+ /// \endcode
JSQS_Single,
/// Always use double quotes.
+ /// \code{.js}
+ /// string1 = "foo";
+ /// string2 = "bar";
+ /// \endcode
JSQS_Double
};
@@ -446,9 +967,27 @@ struct FormatStyle {
JavaScriptQuoteStyle JavaScriptQuotes;
/// \brief Whether to wrap JavaScript import/export statements.
+ /// \code{.js}
+ /// true:
+ /// import {
+ /// VeryLongImportsAreAnnoying,
+ /// VeryLongImportsAreAnnoying,
+ /// VeryLongImportsAreAnnoying,
+ /// } from 'some/module.js'
+ ///
+ /// false:
+ /// import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js"
+ /// \endcode
bool JavaScriptWrapImports;
- /// \brief If true, empty lines at the start of blocks are kept.
+ /// \brief If true, the empty line at the start of blocks is kept.
+ /// \code
+ /// true: false:
+ /// if (foo) { vs. if (foo) {
+ /// bar();
+ /// bar(); }
+ /// }
+ /// \endcode
bool KeepEmptyLinesAtTheStartOfBlocks;
/// \brief Supported languages.
@@ -459,13 +998,13 @@ struct FormatStyle {
enum LanguageKind {
/// Do not use.
LK_None,
- /// Should be used for C, C++, ObjectiveC, ObjectiveC++.
+ /// Should be used for C, C++.
LK_Cpp,
/// Should be used for Java.
LK_Java,
/// Should be used for JavaScript.
LK_JavaScript,
- /// Should be used for ObjC code.
+ /// Should be used for Objective-C, Objective-C++.
LK_ObjC,
/// Should be used for Protocol Buffers
/// (https://developers.google.com/protocol-buffers/).
@@ -473,26 +1012,86 @@ struct FormatStyle {
/// Should be used for TableGen code.
LK_TableGen
};
+ bool isCpp() const { return Language == LK_Cpp || Language == LK_ObjC; }
/// \brief Language, this format style is targeted at.
LanguageKind Language;
/// \brief A regular expression matching macros that start a block.
+ /// \code
+ /// # With:
+ /// MacroBlockBegin: "^NS_MAP_BEGIN|\
+ /// NS_TABLE_HEAD$"
+ /// MacroBlockEnd: "^\
+ /// NS_MAP_END|\
+ /// NS_TABLE_.*_END$"
+ ///
+ /// NS_MAP_BEGIN
+ /// foo();
+ /// NS_MAP_END
+ ///
+ /// NS_TABLE_HEAD
+ /// bar();
+ /// NS_TABLE_FOO_END
+ ///
+ /// # Without:
+ /// NS_MAP_BEGIN
+ /// foo();
+ /// NS_MAP_END
+ ///
+ /// NS_TABLE_HEAD
+ /// bar();
+ /// NS_TABLE_FOO_END
+ /// \endcode
std::string MacroBlockBegin;
/// \brief A regular expression matching macros that end a block.
std::string MacroBlockEnd;
/// \brief The maximum number of consecutive empty lines to keep.
+ /// \code
+ /// MaxEmptyLinesToKeep: 1 vs. MaxEmptyLinesToKeep: 0
+ /// int f() { int f() {
+ /// int = 1; int i = 1;
+ /// i = foo();
+ /// i = foo(); return i;
+ /// }
+ /// return i;
+ /// }
+ /// \endcode
unsigned MaxEmptyLinesToKeep;
/// \brief Different ways to indent namespace contents.
enum NamespaceIndentationKind {
/// Don't indent in namespaces.
+ /// \code
+ /// namespace out {
+ /// int i;
+ /// namespace in {
+ /// int i;
+ /// }
+ /// }
+ /// \endcode
NI_None,
/// Indent only in inner namespaces (nested in other namespaces).
+ /// \code
+ /// namespace out {
+ /// int i;
+ /// namespace in {
+ /// int i;
+ /// }
+ /// }
+ /// \endcode
NI_Inner,
/// Indent in all namespaces.
+ /// \code
+ /// namespace out {
+ /// int i;
+ /// namespace in {
+ /// int i;
+ /// }
+ /// }
+ /// \endcode
NI_All
};
@@ -500,6 +1099,13 @@ struct FormatStyle {
NamespaceIndentationKind NamespaceIndentation;
/// \brief The number of characters to use for indentation of ObjC blocks.
+ /// \code{.objc}
+ /// ObjCBlockIndentWidth: 4
+ ///
+ /// [operation setCompletionBlock:^{
+ /// [self onOperationDone];
+ /// }];
+ /// \endcode
unsigned ObjCBlockIndentWidth;
/// \brief Add a space after ``@property`` in Objective-C, i.e. use
@@ -532,10 +1138,19 @@ struct FormatStyle {
/// \brief The ``&`` and ``*`` alignment style.
enum PointerAlignmentStyle {
/// Align pointer to the left.
+ /// \code
+ /// int* a;
+ /// \endcode
PAS_Left,
/// Align pointer to the right.
+ /// \code
+ /// int *a;
+ /// \endcode
PAS_Right,
/// Align pointer in the middle.
+ /// \code
+ /// int * a;
+ /// \endcode
PAS_Middle
};
@@ -543,31 +1158,81 @@ struct FormatStyle {
PointerAlignmentStyle PointerAlignment;
/// \brief If ``true``, clang-format will attempt to re-flow comments.
+ /// \code
+ /// false:
+ /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
+ /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
+ ///
+ /// true:
+ /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
+ /// // information
+ /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
+ /// * information */
+ /// \endcode
bool ReflowComments;
/// \brief If ``true``, clang-format will sort ``#includes``.
+ /// \code
+ /// false: true:
+ /// #include "b.h" vs. #include "a.h"
+ /// #include "a.h" #include "b.h"
+ /// \endcode
bool SortIncludes;
- /// \brief If ``true``, a space may be inserted after C style casts.
+ /// \brief If ``true``, a space is inserted after C style casts.
+ /// \code
+ /// true: false:
+ /// (int)i; vs. (int) i;
+ /// \endcode
bool SpaceAfterCStyleCast;
/// \brief If \c true, a space will be inserted after the 'template' keyword.
+ /// \code
+ /// true: false:
+ /// template <int> void foo(); vs. template<int> void foo();
+ /// \endcode
bool SpaceAfterTemplateKeyword;
/// \brief If ``false``, spaces will be removed before assignment operators.
+ /// \code
+ /// true: false:
+ /// int a = 5; vs. int a=5;
+ /// a += 42 a+=42;
+ /// \endcode
bool SpaceBeforeAssignmentOperators;
/// \brief Different ways to put a space before opening parentheses.
enum SpaceBeforeParensOptions {
/// Never put a space before opening parentheses.
+ /// \code
+ /// void f() {
+ /// if(true) {
+ /// f();
+ /// }
+ /// }
+ /// \endcode
SBPO_Never,
/// Put a space before opening parentheses only after control statement
/// keywords (``for/if/while...``).
+ /// \code
+ /// void f() {
+ /// if (true) {
+ /// f();
+ /// }
+ /// }
+ /// \endcode
SBPO_ControlStatements,
/// Always put a space before opening parentheses, except when it's
/// prohibited by the syntax rules (in function-like macro definitions) or
/// when determined by other style rules (after unary operators, opening
/// parentheses, etc.)
+ /// \code
+ /// void f () {
+ /// if (true) {
+ /// f ();
+ /// }
+ /// }
+ /// \endcode
SBPO_Always
};
@@ -575,6 +1240,15 @@ struct FormatStyle {
SpaceBeforeParensOptions SpaceBeforeParens;
/// \brief If ``true``, spaces may be inserted into ``()``.
+ /// \code
+ /// true: false:
+ /// void f( ) { vs. void f() {
+ /// int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()};
+ /// if (true) { if (true) {
+ /// f( ); f();
+ /// } }
+ /// } }
+ /// \endcode
bool SpaceInEmptyParentheses;
/// \brief The number of spaces before trailing line comments
@@ -583,30 +1257,63 @@ struct FormatStyle {
/// This does not affect trailing block comments (``/*`` - comments) as
/// those commonly have different usage patterns and a number of special
/// cases.
+ /// \code
+ /// SpacesBeforeTrailingComments: 3
+ /// void f() {
+ /// if (true) { // foo1
+ /// f(); // bar
+ /// } // foo
+ /// }
+ /// \endcode
unsigned SpacesBeforeTrailingComments;
/// \brief If ``true``, spaces will be inserted after ``<`` and before ``>``
/// in template argument lists.
+ /// \code
+ /// true: false:
+ /// static_cast< int >(arg); vs. static_cast<int>(arg);
+ /// std::function< void(int) > fct; std::function<void(int)> fct;
+ /// \endcode
bool SpacesInAngles;
/// \brief If ``true``, spaces are inserted inside container literals (e.g.
/// ObjC and Javascript array and dict literals).
+ /// \code{.js}
+ /// true: false:
+ /// var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3];
+ /// f({a : 1, b : 2, c : 3}); f({a: 1, b: 2, c: 3});
+ /// \endcode
bool SpacesInContainerLiterals;
/// \brief If ``true``, spaces may be inserted into C style casts.
+ /// \code
+ /// true: false:
+ /// x = ( int32 )y vs. x = (int32)y
+ /// \endcode
bool SpacesInCStyleCastParentheses;
/// \brief If ``true``, spaces will be inserted after ``(`` and before ``)``.
+ /// \code
+ /// true: false:
+ /// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
+ /// \endcode
bool SpacesInParentheses;
/// \brief If ``true``, spaces will be inserted after ``[`` and before ``]``.
+ /// Lambdas or unspecified size array declarations will not be affected.
+ /// \code
+ /// true: false:
+ /// int a[ 5 ]; vs. int a[5];
+ /// std::unique_ptr<int[]> foo() {} // Won't be affected
+ /// \endcode
bool SpacesInSquareBrackets;
/// \brief Supported language standards.
enum LanguageStandard {
/// Use C++03-compatible syntax.
LS_Cpp03,
- /// Use features of C++11 (e.g. ``A<A<int>>`` instead of ``A<A<int> >``).
+ /// Use features of C++11, C++14 and C++1z (e.g. ``A<A<int>>`` instead of
+ /// ``A<A<int> >``).
LS_Cpp11,
/// Automatic detection based on the input.
LS_Auto
@@ -668,6 +1375,7 @@ struct FormatStyle {
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
BreakStringLiterals == R.BreakStringLiterals &&
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
+ BreakBeforeInheritanceComma == R.BreakBeforeInheritanceComma &&
ConstructorInitializerAllOnOneLineOrOnePerLine ==
R.ConstructorInitializerAllOnOneLineOrOnePerLine &&
ConstructorInitializerIndentWidth ==
@@ -678,6 +1386,7 @@ struct FormatStyle {
DisableFormat == R.DisableFormat &&
ExperimentalAutoDetectBinPacking ==
R.ExperimentalAutoDetectBinPacking &&
+ FixNamespaceComments == R.FixNamespaceComments &&
ForEachMacros == R.ForEachMacros &&
IncludeCategories == R.IncludeCategories &&
IndentCaseLabels == R.IndentCaseLabels &&
@@ -828,6 +1537,15 @@ tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
StringRef FileName = "<stdin>");
+/// \brief Fix namespace end comments in the given \p Ranges in \p Code.
+///
+/// Returns the ``Replacements`` that fix the namespace comments in all
+/// \p Ranges in \p Code.
+tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
+ StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName = "<stdin>");
+
/// \brief Returns the ``LangOpts`` that the formatter expects you to set.
///
/// \param Style determines specific settings for lexing mode.
@@ -853,23 +1571,27 @@ extern const char *StyleOptionHelpDescription;
/// \param[in] FileName Path to start search for .clang-format if ``StyleName``
/// == "file".
/// \param[in] FallbackStyle The name of a predefined style used to fallback to
-/// in case the style can't be determined from \p StyleName.
+/// in case \p StyleName is "file" and no file can be found.
/// \param[in] Code The actual code to be formatted. Used to determine the
/// language if the filename isn't sufficient.
/// \param[in] FS The underlying file system, in which the file resides. By
/// default, the file system is the real file system.
///
-/// \returns FormatStyle as specified by ``StyleName``. If no style could be
-/// determined, the default is LLVM Style (see ``getLLVMStyle()``).
-FormatStyle getStyle(StringRef StyleName, StringRef FileName,
- StringRef FallbackStyle, StringRef Code = "",
- vfs::FileSystem *FS = nullptr);
+/// \returns FormatStyle as specified by ``StyleName``. If ``StyleName`` is
+/// "file" and no file is found, returns ``FallbackStyle``. If no style could be
+/// determined, returns an Error.
+llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
+ StringRef FallbackStyle,
+ StringRef Code = "",
+ vfs::FileSystem *FS = nullptr);
// \brief Returns a string representation of ``Language``.
inline StringRef getLanguageName(FormatStyle::LanguageKind Language) {
switch (Language) {
case FormatStyle::LK_Cpp:
return "C++";
+ case FormatStyle::LK_ObjC:
+ return "Objective-C";
case FormatStyle::LK_Java:
return "Java";
case FormatStyle::LK_JavaScript:
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
index b76bfcbe4663..53975a07ea94 100644
--- a/include/clang/Frontend/ASTConsumers.h
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -37,7 +37,7 @@ std::unique_ptr<ASTConsumer> CreateASTPrinter(std::unique_ptr<raw_ostream> OS,
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging.
std::unique_ptr<ASTConsumer> CreateASTDumper(StringRef FilterString,
- bool DumpDecls,
+ bool DumpDecls, bool Deserialize,
bool DumpLookups);
// AST Decl node lister: prints qualified names of all filterable AST Decl
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index b1cdb46d505b..2a8df1b7b9ae 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -51,6 +51,7 @@ class DiagnosticsEngine;
class FileEntry;
class FileManager;
class HeaderSearch;
+class MemoryBufferCache;
class Preprocessor;
class PCHContainerOperations;
class PCHContainerReader;
@@ -84,6 +85,7 @@ private:
IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
IntrusiveRefCntPtr<FileManager> FileMgr;
IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ IntrusiveRefCntPtr<MemoryBufferCache> PCMCache;
std::unique_ptr<HeaderSearch> HeaderInfo;
IntrusiveRefCntPtr<TargetInfo> Target;
std::shared_ptr<Preprocessor> PP;
@@ -519,6 +521,8 @@ public:
const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
+ IntrusiveRefCntPtr<ASTReader> getASTReader() const;
+
StringRef getOriginalSourceFileName() {
return OriginalSourceFile;
}
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 964a6cc2a007..9565b22e7059 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -65,8 +65,6 @@ CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA.
CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO.
CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata.
CODEGENOPT(EmulatedTLS , 1, 0) ///< Set when -femulated-tls is enabled.
-/// \brief FP_CONTRACT mode (on/off/fast).
-ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On)
/// \brief Embed Bitcode mode (off/all/bitcode/marker).
ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off)
CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
@@ -83,12 +81,15 @@ CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is
VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200)
CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled.
+CODEGENOPT(CallFEntry , 1, 0) ///< Set when -mfentry is enabled.
CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to
///< be generated.
CODEGENOPT(PrepareForLTO , 1, 0) ///< Set when -flto is enabled on the
///< compile step.
CODEGENOPT(EmitSummaryIndex, 1, 0) ///< Set when -flto=thin is enabled on the
///< compile step.
+CODEGENOPT(LTOUnit, 1, 0) ///< Emit IR to support LTO unit features (CFI, whole
+ ///< program vtable opt).
CODEGENOPT(IncrementalLinkerCompatible, 1, 0) ///< Emit an object file which can
///< be used with an incremental
///< linker.
@@ -221,6 +222,9 @@ VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
/// The kind of generated debug info.
ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 3, codegenoptions::NoDebugInfo)
+/// Whether to generate macro debug info.
+CODEGENOPT(MacroDebugInfo, 1, 0)
+
/// Tune the debug info for this debugger.
ENUM_CODEGENOPT(DebuggerTuning, llvm::DebuggerKind, 2,
llvm::DebuggerKind::Default)
@@ -256,6 +260,12 @@ CODEGENOPT(PIECopyRelocations, 1, 0)
/// paths that reach the end of a function without executing a required return.
CODEGENOPT(StrictReturn, 1, 1)
+/// Whether emit extra debug info for sample pgo profile collection.
+CODEGENOPT(DebugInfoForProfiling, 1, 0)
+
+/// Whether 3-component vector type is preserved.
+CODEGENOPT(PreserveVec3Type, 1, 0)
+
#undef CODEGENOPT
#undef ENUM_CODEGENOPT
#undef VALUE_CODEGENOPT
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 52bd1c5aff79..22d5d3d16ee2 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -69,12 +69,6 @@ public:
LocalExecTLSModel
};
- enum FPContractModeKind {
- FPC_Off, // Form fused FP ops only where result will not be affected.
- FPC_On, // Form fused FP ops according to FP_CONTRACT rules.
- FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
- };
-
enum StructReturnConventionKind {
SRCK_Default, // No special option was passed.
SRCK_OnStack, // Small structs on the stack (-fpcc-struct-return).
@@ -130,8 +124,21 @@ public:
/// The float precision limit to use, if non-empty.
std::string LimitFloatPrecision;
- /// The name of the bitcode file to link before optzns.
- std::vector<std::pair<unsigned, std::string>> LinkBitcodeFiles;
+ struct BitcodeFileToLink {
+ /// The filename of the bitcode file to link in.
+ std::string Filename;
+ /// If true, we set attributes functions in the bitcode library according to
+ /// our CodeGenOptions, much as we set attrs on functions that we generate
+ /// ourselves.
+ bool PropagateAttrs = false;
+ /// If true, we use LLVM module internalizer.
+ bool Internalize = false;
+ /// Bitwise combination of llvm::Linker::Flags, passed to the LLVM linker.
+ unsigned LinkFlags = 0;
+ };
+
+ /// The files specified here are linked in to the module before optimizations.
+ std::vector<BitcodeFileToLink> LinkBitcodeFiles;
/// The user provided name for the "main file", if non-empty. This is useful
/// in situations where the input file name does not match the original input
@@ -175,6 +182,11 @@ public:
/// importing.
std::string ThinLTOIndexFile;
+ /// Name of a file that can optionally be written with minimized bitcode
+ /// to be used as input for the ThinLTO thin link step, which only needs
+ /// the summary and module symbol table (and not, e.g. any debug metadata).
+ std::string ThinLinkBitcodeFile;
+
/// A list of file names passed with -fcuda-include-gpubinary options to
/// forward to CUDA runtime back-end for incorporating them into host-side
/// object file.
@@ -206,7 +218,7 @@ public:
/// flag.
std::shared_ptr<llvm::Regex> OptimizationRemarkAnalysisPattern;
- /// Set of files definining the rules for the symbol rewriting.
+ /// Set of files defining the rules for the symbol rewriting.
std::vector<std::string> RewriteMapFiles;
/// Set of sanitizer checks that are non-fatal (i.e. execution should be
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 3ebbc61515c6..4f7149fcb8b3 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -44,6 +44,7 @@ class ExternalASTSource;
class FileEntry;
class FileManager;
class FrontendAction;
+class MemoryBufferCache;
class Module;
class Preprocessor;
class Sema;
@@ -90,6 +91,9 @@ class CompilerInstance : public ModuleLoader {
/// The source manager.
IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ /// The cache of PCM files.
+ IntrusiveRefCntPtr<MemoryBufferCache> PCMCache;
+
/// The preprocessor.
std::shared_ptr<Preprocessor> PP;
@@ -142,13 +146,13 @@ class CompilerInstance : public ModuleLoader {
/// \brief Whether we should (re)build the global module index once we
/// have finished with this translation unit.
- bool BuildGlobalModuleIndex;
+ bool BuildGlobalModuleIndex = false;
/// \brief We have a full global module index, with all modules.
- bool HaveFullGlobalModuleIndex;
+ bool HaveFullGlobalModuleIndex = false;
/// \brief One or more modules failed to build.
- bool ModuleBuildFailed;
+ bool ModuleBuildFailed = false;
/// \brief Holds information about the output file.
///
@@ -178,7 +182,7 @@ public:
explicit CompilerInstance(
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
std::make_shared<PCHContainerOperations>(),
- bool BuildingModule = false);
+ MemoryBufferCache *SharedPCMCache = nullptr);
~CompilerInstance() override;
/// @name High-Level Operations
@@ -658,6 +662,8 @@ public:
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
+ DependencyFileGenerator *DependencyFile,
+ ArrayRef<std::shared_ptr<DependencyCollector>> DependencyCollectors,
void *DeserializationListener, bool OwnDeserializationListener,
bool Preamble, bool UseGlobalModuleIndex);
@@ -783,6 +789,8 @@ public:
}
void setExternalSemaSource(IntrusiveRefCntPtr<ExternalSemaSource> ESS);
+
+ MemoryBufferCache &getPCMCache() const { return *PCMCache; }
};
} // end namespace clang
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 20fddc4d5a52..778b40b15df7 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -80,6 +80,8 @@ protected:
bool hasASTFileSupport() const override { return false; }
+ bool shouldEraseOutputFiles() override;
+
public:
/// \brief Compute the AST consumer arguments that will be used to
/// create the PCHGenerator instance returned by CreateASTConsumer.
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 9c960bb0c305..4fd0f82a3ad2 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -81,7 +81,7 @@ enum InputKind {
IK_LLVM_IR
};
-
+
/// \brief An input file for the front end.
class FrontendInputFile {
/// \brief The file name, or "-" to read from standard input.
@@ -109,6 +109,13 @@ public:
bool isEmpty() const { return File.empty() && Buffer == nullptr; }
bool isFile() const { return !isBuffer(); }
bool isBuffer() const { return Buffer != nullptr; }
+ bool isPreprocessed() const {
+ return Kind == IK_PreprocessedC ||
+ Kind == IK_PreprocessedCXX ||
+ Kind == IK_PreprocessedObjC ||
+ Kind == IK_PreprocessedObjCXX ||
+ Kind == IK_PreprocessedCuda;
+ }
StringRef getFile() const {
assert(isFile());
@@ -150,6 +157,8 @@ public:
///< global module index if needed.
unsigned ASTDumpDecls : 1; ///< Whether we include declaration
///< dumps in AST dumps.
+ unsigned ASTDumpAll : 1; ///< Whether we deserialize all decls
+ ///< when forming AST dumps.
unsigned ASTDumpLookups : 1; ///< Whether we include lookup table
///< dumps in AST dumps.
unsigned BuildingImplicitModule : 1; ///< Whether we are performing an
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index 8021d08942e5..5ead90f00721 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -29,7 +29,8 @@ enum LangFeatures {
Digraphs = (1 << 8),
GNUMode = (1 << 9),
HexFloat = (1 << 10),
- ImplicitInt = (1 << 11)
+ ImplicitInt = (1 << 11),
+ OpenCL = (1 << 12)
};
}
@@ -91,6 +92,9 @@ public:
/// hasImplicitInt - Language allows variables to be typed as int implicitly.
bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; }
+ /// isOpenCL - Language is a OpenCL variant.
+ bool isOpenCL() const { return Flags & frontend::OpenCL; }
+
static const LangStandard &getLangStandardForKind(Kind K);
static const LangStandard *getLangStandardForName(StringRef Name);
};
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index 06fe1a3350ce..425ac84bf6ff 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -142,16 +142,16 @@ LANGSTANDARD(gnucxx1z, "gnu++1z",
// OpenCL
LANGSTANDARD(opencl, "cl",
"OpenCL 1.0",
- LineComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat | OpenCL)
LANGSTANDARD(opencl11, "cl1.1",
"OpenCL 1.1",
- LineComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat | OpenCL)
LANGSTANDARD(opencl12, "cl1.2",
"OpenCL 1.2",
- LineComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat | OpenCL)
LANGSTANDARD(opencl20, "cl2.0",
"OpenCL 2.0",
- LineComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat | OpenCL)
LANGSTANDARD_ALIAS(opencl, "CL")
LANGSTANDARD_ALIAS(opencl11, "CL1.1")
diff --git a/include/clang/Frontend/PCHContainerOperations.h b/include/clang/Frontend/PCHContainerOperations.h
index d323fb3e8b94..f9a73508d700 100644
--- a/include/clang/Frontend/PCHContainerOperations.h
+++ b/include/clang/Frontend/PCHContainerOperations.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_PCH_CONTAINER_OPERATIONS_H
#define LLVM_CLANG_PCH_CONTAINER_OPERATIONS_H
+#include "clang/Basic/Module.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -29,7 +30,7 @@ class DiagnosticsEngine;
class CompilerInstance;
struct PCHBuffer {
- uint64_t Signature;
+ ASTFileSignature Signature;
llvm::SmallVector<char, 0> Data;
bool IsComplete;
};
diff --git a/include/clang/Index/IndexSymbol.h b/include/clang/Index/IndexSymbol.h
index d19e5ebef2f0..217d6b1fb1cc 100644
--- a/include/clang/Index/IndexSymbol.h
+++ b/include/clang/Index/IndexSymbol.h
@@ -51,6 +51,8 @@ enum class SymbolKind : uint8_t {
Constructor,
Destructor,
ConversionFunction,
+
+ Parameter,
};
enum class SymbolLanguage {
@@ -77,8 +79,9 @@ enum class SymbolProperty : uint8_t {
IBAnnotated = 1 << 4,
IBOutletCollection = 1 << 5,
GKInspectable = 1 << 6,
+ Local = 1 << 7,
};
-static const unsigned SymbolPropertyBitNum = 7;
+static const unsigned SymbolPropertyBitNum = 8;
typedef unsigned SymbolPropertySet;
/// Set of roles that are attributed to symbol occurrences.
@@ -125,8 +128,12 @@ struct SymbolInfo {
SymbolInfo getSymbolInfo(const Decl *D);
+bool isFunctionLocalSymbol(const Decl *D);
+
void applyForEachSymbolRole(SymbolRoleSet Roles,
llvm::function_ref<void(SymbolRole)> Fn);
+bool applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles,
+ llvm::function_ref<bool(SymbolRole)> Fn);
void printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS);
/// \returns true if no name was printed, false otherwise.
diff --git a/include/clang/Index/IndexingAction.h b/include/clang/Index/IndexingAction.h
index e2e63dc6357d..8eed33c61227 100644
--- a/include/clang/Index/IndexingAction.h
+++ b/include/clang/Index/IndexingAction.h
@@ -14,9 +14,14 @@
#include <memory>
namespace clang {
+ class ASTReader;
class ASTUnit;
class FrontendAction;
+namespace serialization {
+ class ModuleFile;
+}
+
namespace index {
class IndexDataConsumer;
@@ -42,6 +47,11 @@ void indexASTUnit(ASTUnit &Unit,
std::shared_ptr<IndexDataConsumer> DataConsumer,
IndexingOptions Opts);
+void indexModuleFile(serialization::ModuleFile &Mod,
+ ASTReader &Reader,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts);
+
} // namespace index
} // namespace clang
diff --git a/include/clang/Index/USRGeneration.h b/include/clang/Index/USRGeneration.h
index be89068469c4..61f2c9d1ff13 100644
--- a/include/clang/Index/USRGeneration.h
+++ b/include/clang/Index/USRGeneration.h
@@ -16,6 +16,7 @@
namespace clang {
class Decl;
class MacroDefinitionRecord;
+class SourceLocation;
class SourceManager;
namespace index {
@@ -54,6 +55,8 @@ void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS);
/// \returns true on error, false on success.
bool generateUSRForMacro(const MacroDefinitionRecord *MD,
const SourceManager &SM, SmallVectorImpl<char> &Buf);
+bool generateUSRForMacro(StringRef MacroName, SourceLocation Loc,
+ const SourceManager &SM, SmallVectorImpl<char> &Buf);
} // namespace index
} // namespace clang
diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h
index e99980537348..ca3a84e75e18 100644
--- a/include/clang/Lex/HeaderSearchOptions.h
+++ b/include/clang/Lex/HeaderSearchOptions.h
@@ -178,6 +178,8 @@ public:
unsigned ModulesValidateDiagnosticOptions : 1;
+ unsigned ModulesHashContent : 1;
+
HeaderSearchOptions(StringRef _Sysroot = "/")
: Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(0),
ImplicitModuleMaps(0), ModuleMapFileHomeIsCwd(0),
@@ -186,8 +188,8 @@ public:
UseBuiltinIncludes(true), UseStandardSystemIncludes(true),
UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false),
ModulesValidateOncePerBuildSession(false),
- ModulesValidateSystemHeaders(false),
- UseDebugInfo(false), ModulesValidateDiagnosticOptions(true) {}
+ ModulesValidateSystemHeaders(false), UseDebugInfo(false),
+ ModulesValidateDiagnosticOptions(true), ModulesHashContent(false) {}
/// AddPath - Add the \p Path path to the specified \p Group list.
void AddPath(StringRef Path, frontend::IncludeDirGroup Group,
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 7ce1aad36d12..3efe914daaee 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -47,6 +47,7 @@ class ExternalPreprocessorSource;
class FileManager;
class FileEntry;
class HeaderSearch;
+class MemoryBufferCache;
class PragmaNamespace;
class PragmaHandler;
class CommentHandler;
@@ -102,6 +103,7 @@ class Preprocessor {
const TargetInfo *AuxTarget;
FileManager &FileMgr;
SourceManager &SourceMgr;
+ MemoryBufferCache &PCMCache;
std::unique_ptr<ScratchBuffer> ScratchBuf;
HeaderSearch &HeaderInfo;
ModuleLoader &TheModuleLoader;
@@ -652,6 +654,7 @@ class Preprocessor {
public:
Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM,
+ MemoryBufferCache &PCMCache,
HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup = nullptr,
bool OwnsHeaderSearch = false,
@@ -691,6 +694,7 @@ public:
const TargetInfo *getAuxTargetInfo() const { return AuxTarget; }
FileManager &getFileManager() const { return FileMgr; }
SourceManager &getSourceManager() const { return SourceMgr; }
+ MemoryBufferCache &getPCMCache() const { return PCMCache; }
HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
IdentifierTable &getIdentifierTable() { return Identifiers; }
@@ -1077,6 +1081,24 @@ public:
/// \brief Disable the last EnableBacktrackAtThisPos call.
void CommitBacktrackedTokens();
+ struct CachedTokensRange {
+ CachedTokensTy::size_type Begin, End;
+ };
+
+private:
+ /// \brief A range of cached tokens that should be erased after lexing
+ /// when backtracking requires the erasure of such cached tokens.
+ Optional<CachedTokensRange> CachedTokenRangeToErase;
+
+public:
+ /// \brief Returns the range of cached tokens that were lexed since
+ /// EnableBacktrackAtThisPos() was previously called.
+ CachedTokensRange LastCachedTokenRange();
+
+ /// \brief Erase the range of cached tokens that were lexed since
+ /// EnableBacktrackAtThisPos() was previously called.
+ void EraseCachedTokens(CachedTokensRange TokenRange);
+
/// \brief Make Preprocessor re-lex the tokens that were lexed since
/// EnableBacktrackAtThisPos() was previously called.
void Backtrack();
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index fe159022c223..5f4e5fb4b215 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -142,6 +142,10 @@ class Parser : public CodeCompletionHandler {
/// \brief Identifier for "replacement".
IdentifierInfo *Ident_replacement;
+ /// Identifiers used by the 'external_source_symbol' attribute.
+ IdentifierInfo *Ident_language, *Ident_defined_in,
+ *Ident_generated_declaration;
+
/// C++0x contextual keywords.
mutable IdentifierInfo *Ident_final;
mutable IdentifierInfo *Ident_GNU_final;
@@ -179,6 +183,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> LoopHintHandler;
std::unique_ptr<PragmaHandler> UnrollHintHandler;
std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
+ std::unique_ptr<PragmaHandler> FPHandler;
std::unique_ptr<CommentHandler> CommentSemaHandler;
@@ -545,6 +550,10 @@ private:
void HandlePragmaFPContract();
/// \brief Handle the annotation token produced for
+ /// #pragma clang fp ...
+ void HandlePragmaFP();
+
+ /// \brief Handle the annotation token produced for
/// #pragma OPENCL EXTENSION...
void HandlePragmaOpenCLExtension();
@@ -791,6 +800,14 @@ private:
/// \brief Consume any extra semi-colons until the end of the line.
void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified);
+ /// Return false if the next token is an identifier. An 'expected identifier'
+ /// error is emitted otherwise.
+ ///
+ /// The parser tries to recover from the error by checking if the next token
+ /// is a C++ keyword when parsing Objective-C++. Return false if the recovery
+ /// was successful.
+ bool expectIdentifier();
+
public:
//===--------------------------------------------------------------------===//
// Scope manipulation
@@ -1445,10 +1462,12 @@ private:
ExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
- TypeCastState isTypeCast);
+ TypeCastState isTypeCast,
+ bool isVectorLiteral = false);
ExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand = false,
- TypeCastState isTypeCast = NotTypeCast);
+ TypeCastState isTypeCast = NotTypeCast,
+ bool isVectorLiteral = false);
/// Returns true if the next token cannot start an expression.
bool isNotExpressionStart();
@@ -1530,7 +1549,8 @@ private:
bool EnteringContext,
bool *MayBePseudoDestructor = nullptr,
bool IsTypename = false,
- IdentifierInfo **LastII = nullptr);
+ IdentifierInfo **LastII = nullptr,
+ bool OnlyNamespace = false);
//===--------------------------------------------------------------------===//
// C++0x 5.1.2: Lambda expressions
@@ -1682,7 +1702,7 @@ private:
StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr,
bool AllowOpenMPStandalone = false);
- enum AllowedContsructsKind {
+ enum AllowedConstructsKind {
/// \brief Allow any declarations, statements, OpenMP directives.
ACK_Any,
/// \brief Allow only statements and non-standalone OpenMP directives.
@@ -1691,11 +1711,11 @@ private:
ACK_StatementsOpenMPAnyExecutable
};
StmtResult
- ParseStatementOrDeclaration(StmtVector &Stmts, AllowedContsructsKind Allowed,
+ ParseStatementOrDeclaration(StmtVector &Stmts, AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc = nullptr);
StmtResult ParseStatementOrDeclarationAfterAttributes(
StmtVector &Stmts,
- AllowedContsructsKind Allowed,
+ AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
StmtResult ParseExprStatement();
@@ -1724,7 +1744,7 @@ private:
StmtResult ParseAsmStatement(bool &msAsm);
StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
StmtResult ParsePragmaLoopHint(StmtVector &Stmts,
- AllowedContsructsKind Allowed,
+ AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
@@ -1834,6 +1854,26 @@ private:
llvm_unreachable("Missing DeclSpecContext case");
}
+ /// Is this a context in which we can perform class template argument
+ /// deduction?
+ static bool isClassTemplateDeductionContext(DeclSpecContext DSC) {
+ switch (DSC) {
+ case DSC_normal:
+ case DSC_class:
+ case DSC_top_level:
+ case DSC_condition:
+ case DSC_type_specifier:
+ return true;
+
+ case DSC_objc_method_result:
+ case DSC_template_type_arg:
+ case DSC_trailing:
+ case DSC_alias_declaration:
+ return false;
+ }
+ llvm_unreachable("Missing DeclSpecContext case");
+ }
+
/// Information on a C++0x for-range-initializer found while parsing a
/// declaration which turns out to be a for-range-declaration.
struct ForRangeInit {
@@ -1947,7 +1987,7 @@ private:
/// \brief Starting with a scope specifier, identifier, or
/// template-id that refers to the current class, determine whether
/// this is a constructor declarator.
- bool isConstructorDeclarator(bool Unqualified);
+ bool isConstructorDeclarator(bool Unqualified, bool DeductionGuide = false);
/// \brief Specifies the context in which type-id/expression
/// disambiguation will occur.
@@ -2177,6 +2217,12 @@ private:
Declarator *D);
IdentifierLoc *ParseIdentifierLoc();
+ unsigned
+ ParseClangAttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs, SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax);
+
void MaybeParseCXX11Attributes(Declarator &D) {
if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
@@ -2266,6 +2312,14 @@ private:
Optional<AvailabilitySpec> ParseAvailabilitySpec();
ExprResult ParseAvailabilityCheckExpr(SourceLocation StartLoc);
+ void ParseExternalSourceSymbolAttribute(IdentifierInfo &ExternalSourceSymbol,
+ SourceLocation Loc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax);
+
void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
SourceLocation ObjCBridgeRelatedLoc,
ParsedAttributes &attrs,
@@ -2365,10 +2419,10 @@ private:
AR_DeclspecAttributesParsed
};
- void ParseTypeQualifierListOpt(DeclSpec &DS,
- unsigned AttrReqs = AR_AllAttributesParsed,
- bool AtomicAllowed = true,
- bool IdentifierRequired = false);
+ void ParseTypeQualifierListOpt(
+ DeclSpec &DS, unsigned AttrReqs = AR_AllAttributesParsed,
+ bool AtomicAllowed = true, bool IdentifierRequired = false,
+ Optional<llvm::function_ref<void()>> CodeCompletionHandler = None);
void ParseDirectDeclarator(Declarator &D);
void ParseDecompositionDeclarator(Declarator &D);
void ParseParenDeclarator(Declarator &D);
@@ -2549,7 +2603,7 @@ private:
/// executable directives are allowed.
///
StmtResult
- ParseOpenMPDeclarativeOrExecutableDirective(AllowedContsructsKind Allowed);
+ ParseOpenMPDeclarativeOrExecutableDirective(AllowedConstructsKind Allowed);
/// \brief Parses clause of kind \a CKind for directive of a kind \a Kind.
///
/// \param DKind Kind of current directive.
@@ -2614,6 +2668,7 @@ public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
+ bool AllowDeductionGuide,
ParsedType ObjectType,
SourceLocation& TemplateKWLoc,
UnqualifiedId &Result);
@@ -2674,7 +2729,7 @@ private:
SourceLocation TemplateKWLoc,
UnqualifiedId &TemplateName,
bool AllowTypeAnnotation = true);
- void AnnotateTemplateIdTokenAsType();
+ void AnnotateTemplateIdTokenAsType(bool IsClassName = false);
bool IsTemplateArgumentList(unsigned Skip = 0);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
ParsedTemplateArgument ParseTemplateTemplateArgument();
diff --git a/lib/Parse/RAIIObjectsForParser.h b/include/clang/Parse/RAIIObjectsForParser.h
index 36d87ebd8aca..0422b038da65 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/include/clang/Parse/RAIIObjectsForParser.h
@@ -18,6 +18,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Sema.h"
namespace clang {
@@ -442,6 +443,25 @@ namespace clang {
void skipToEnd();
};
+ /// \brief RAIIObject to destroy the contents of a SmallVector of
+ /// TemplateIdAnnotation pointers and clear the vector.
+ class DestroyTemplateIdAnnotationsRAIIObj {
+ SmallVectorImpl<TemplateIdAnnotation *> &Container;
+
+ public:
+ DestroyTemplateIdAnnotationsRAIIObj(
+ SmallVectorImpl<TemplateIdAnnotation *> &Container)
+ : Container(Container) {}
+
+ ~DestroyTemplateIdAnnotationsRAIIObj() {
+ for (SmallVectorImpl<TemplateIdAnnotation *>::iterator I =
+ Container.begin(),
+ E = Container.end();
+ I != E; ++I)
+ (*I)->Destroy();
+ Container.clear();
+ }
+ };
} // end namespace clang
#endif
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index e74bf6a7cc86..7c1678086c2f 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -927,6 +927,7 @@ enum AttributeDeclKind {
ExpectedStructClassVariableFunctionOrInlineNamespace,
ExpectedForMaybeUnused,
ExpectedEnumOrClass,
+ ExpectedNamedDecl,
};
} // end namespace clang
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 331fd0db6724..df5e1050367e 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -519,7 +519,7 @@ public:
SourceRange getTypeofParensRange() const { return TypeofParensRange; }
void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
- bool containsPlaceholderType() const {
+ bool hasAutoTypeSpec() const {
return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type ||
TypeSpecType == TST_decltype_auto);
}
@@ -819,7 +819,9 @@ public:
: objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr),
Nullability(0), GetterName(nullptr), SetterName(nullptr) { }
- ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; }
+ ObjCDeclQualifier getObjCDeclQualifier() const {
+ return (ObjCDeclQualifier)objcDeclQualifier;
+ }
void setObjCDeclQualifier(ObjCDeclQualifier DQVal) {
objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal);
}
@@ -859,17 +861,25 @@ public:
const IdentifierInfo *getGetterName() const { return GetterName; }
IdentifierInfo *getGetterName() { return GetterName; }
- void setGetterName(IdentifierInfo *name) { GetterName = name; }
+ SourceLocation getGetterNameLoc() const { return GetterNameLoc; }
+ void setGetterName(IdentifierInfo *name, SourceLocation loc) {
+ GetterName = name;
+ GetterNameLoc = loc;
+ }
const IdentifierInfo *getSetterName() const { return SetterName; }
IdentifierInfo *getSetterName() { return SetterName; }
- void setSetterName(IdentifierInfo *name) { SetterName = name; }
+ SourceLocation getSetterNameLoc() const { return SetterNameLoc; }
+ void setSetterName(IdentifierInfo *name, SourceLocation loc) {
+ SetterName = name;
+ SetterNameLoc = loc;
+ }
private:
// FIXME: These two are unrelated and mutually exclusive. So perhaps
// we can put them in a union to reflect their mutual exclusivity
// (space saving is negligible).
- ObjCDeclQualifier objcDeclQualifier : 7;
+ unsigned objcDeclQualifier : 7;
// NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
unsigned PropertyAttributes : 15;
@@ -880,6 +890,9 @@ private:
IdentifierInfo *GetterName; // getter name or NULL if no getter
IdentifierInfo *SetterName; // setter name or NULL if no setter
+ SourceLocation GetterNameLoc; // location of the getter attribute's value
+ SourceLocation SetterNameLoc; // location of the setter attribute's value
+
};
/// \brief Represents a C++ unqualified-id that has been parsed.
@@ -908,7 +921,9 @@ public:
/// \brief A template-id, e.g., f<int>.
IK_TemplateId,
/// \brief An implicit 'self' parameter
- IK_ImplicitSelfParam
+ IK_ImplicitSelfParam,
+ /// \brief A deduction-guide name (a template-name)
+ IK_DeductionGuideName
} Kind;
struct OFI {
@@ -928,8 +943,8 @@ public:
/// \brief Anonymous union that holds extra data associated with the
/// parsed unqualified-id.
union {
- /// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind
- /// == IK_UserLiteralId, the identifier suffix.
+ /// \brief When Kind == IK_Identifier, the parsed identifier, or when
+ /// Kind == IK_UserLiteralId, the identifier suffix.
IdentifierInfo *Identifier;
/// \brief When Kind == IK_OperatorFunctionId, the overloaded operator
@@ -947,6 +962,9 @@ public:
/// \brief When Kind == IK_DestructorName, the type referred to by the
/// class-name.
UnionParsedType DestructorName;
+
+ /// \brief When Kind == IK_DeductionGuideName, the parsed template-name.
+ UnionParsedTemplateTy TemplateName;
/// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId,
/// the template-id annotation that contains the template name and
@@ -1085,6 +1103,18 @@ public:
/// \p TemplateId and will free it on destruction.
void setTemplateId(TemplateIdAnnotation *TemplateId);
+ /// \brief Specify that this unqualified-id was parsed as a template-name for
+ /// a deduction-guide.
+ ///
+ /// \param Template The parsed template-name.
+ /// \param TemplateLoc The location of the parsed template-name.
+ void setDeductionGuideName(ParsedTemplateTy Template,
+ SourceLocation TemplateLoc) {
+ Kind = IK_DeductionGuideName;
+ TemplateName = Template;
+ StartLocation = EndLocation = TemplateLoc;
+ }
+
/// \brief Return the source range that covers this unqualified-id.
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(StartLocation, EndLocation);
@@ -1709,6 +1739,7 @@ public:
ObjCParameterContext,// An ObjC method parameter type.
KNRTypeListContext, // K&R type definition list for formals.
TypeNameContext, // Abstract declarator for types.
+ FunctionalCastContext, // Type in a C++ functional cast expression.
MemberContext, // Struct/Union field.
BlockContext, // Declaration within a block in a function.
ForContext, // Declaration within first part of a for loop.
@@ -1911,6 +1942,7 @@ public:
return false;
case TypeNameContext:
+ case FunctionalCastContext:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
@@ -1951,6 +1983,7 @@ public:
return true;
case TypeNameContext:
+ case FunctionalCastContext:
case CXXNewContext:
case AliasDeclContext:
case AliasTemplateContext:
@@ -1983,6 +2016,7 @@ public:
case CXXCatchContext:
case ObjCCatchContext:
case TypeNameContext:
+ case FunctionalCastContext:
case ConversionIdContext:
case ObjCParameterContext:
case ObjCResultContext:
@@ -2021,6 +2055,7 @@ public:
// These contexts don't allow any kind of non-abstract declarator.
case KNRTypeListContext:
case TypeNameContext:
+ case FunctionalCastContext:
case AliasDeclContext:
case AliasTemplateContext:
case LambdaExprParameterContext:
@@ -2078,6 +2113,7 @@ public:
case CXXCatchContext:
case ObjCCatchContext:
case TypeNameContext:
+ case FunctionalCastContext: // FIXME
case CXXNewContext:
case AliasDeclContext:
case AliasTemplateContext:
@@ -2279,6 +2315,7 @@ public:
case ConditionContext:
case KNRTypeListContext:
case TypeNameContext:
+ case FunctionalCastContext:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
@@ -2312,6 +2349,16 @@ public:
return true;
}
+ /// \brief Determine whether a trailing return type was written (at any
+ /// level) within this declarator.
+ bool hasTrailingReturnType() const {
+ for (const auto &Chunk : type_objects())
+ if (Chunk.Kind == DeclaratorChunk::Function &&
+ Chunk.Fun.hasTrailingReturnType())
+ return true;
+ return false;
+ }
+
/// takeAttributes - Takes attributes from the given parsed-attributes
/// set and add them to this declarator.
///
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index a07834f95629..382fe80bea7d 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -73,12 +73,10 @@ public:
typedef std::input_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
- /// Ptr - There are 3 forms that 'Ptr' represents:
+ /// Ptr - There are 2 forms that 'Ptr' represents:
/// 1) A single NamedDecl. (Ptr & 0x1 == 0)
/// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the
- /// same declaration context. (Ptr & 0x3 == 0x1)
- /// 3) A IdDeclInfo::DeclsTy::iterator that traverses the decls of parent
- /// declaration contexts too. (Ptr & 0x3 == 0x3)
+ /// same declaration context. (Ptr & 0x1 == 0x1)
uintptr_t Ptr;
typedef IdDeclInfo::DeclsTy::iterator BaseIter;
@@ -97,7 +95,7 @@ public:
BaseIter getIterator() const {
assert(isIterator() && "Ptr not an iterator!");
- return reinterpret_cast<BaseIter>(Ptr & ~0x3);
+ return reinterpret_cast<BaseIter>(Ptr & ~0x1);
}
friend class IdentifierResolver;
@@ -128,14 +126,6 @@ public:
incrementSlowCase();
return *this;
}
-
- uintptr_t getAsOpaqueValue() const { return Ptr; }
-
- static iterator getFromOpaqueValue(uintptr_t P) {
- iterator Result;
- Result.Ptr = P;
- return Result;
- }
};
/// begin - Returns an iterator for decls with the name 'Name'.
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 94be58ac8aeb..bd07b9ea9aee 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -70,6 +70,9 @@ public:
/// \brief The entity being initialized is a field of block descriptor for
/// the copied-in c++ object.
EK_BlockElement,
+ /// The entity being initialized is a field of block descriptor for the
+ /// copied-in lambda object that's used in the lambda to block conversion.
+ EK_LambdaToBlockConversionBlockElement,
/// \brief The entity being initialized is the real or imaginary part of a
/// complex number.
EK_ComplexElement,
@@ -260,7 +263,13 @@ public:
QualType Type, bool NRVO) {
return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO);
}
-
+
+ static InitializedEntity InitializeLambdaToBlock(SourceLocation BlockVarLoc,
+ QualType Type, bool NRVO) {
+ return InitializedEntity(EK_LambdaToBlockConversionBlockElement,
+ BlockVarLoc, Type, NRVO);
+ }
+
/// \brief Create the initialization entity for an exception object.
static InitializedEntity InitializeException(SourceLocation ThrowLoc,
QualType Type, bool NRVO) {
@@ -274,15 +283,18 @@ public:
/// \brief Create the initialization entity for a temporary.
static InitializedEntity InitializeTemporary(QualType Type) {
- InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
- Result.TypeInfo = nullptr;
- return Result;
+ return InitializeTemporary(nullptr, Type);
}
/// \brief Create the initialization entity for a temporary.
static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) {
- InitializedEntity Result(EK_Temporary, SourceLocation(),
- TypeInfo->getType());
+ return InitializeTemporary(TypeInfo, TypeInfo->getType());
+ }
+
+ /// \brief Create the initialization entity for a temporary.
+ static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo,
+ QualType Type) {
+ InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
Result.TypeInfo = TypeInfo;
return Result;
}
@@ -579,6 +591,16 @@ public:
return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal,
InitLoc, LParenLoc, RParenLoc);
}
+
+ /// \brief Create an initialization from an initializer (which, for direct
+ /// initialization from a parenthesized list, will be a ParenListExpr).
+ static InitializationKind CreateForInit(SourceLocation Loc, bool DirectInit,
+ Expr *Init) {
+ if (!Init) return CreateDefault(Loc);
+ if (!DirectInit) return CreateCopy(Loc, Init->getLocStart());
+ if (isa<InitListExpr>(Init)) return CreateDirectList(Loc);
+ return CreateDirect(Loc, Init->getLocStart(), Init->getLocEnd());
+ }
/// \brief Determine the initialization kind.
InitKind getKind() const {
@@ -809,6 +831,8 @@ public:
enum FailureKind {
/// \brief Too many initializers provided for a reference.
FK_TooManyInitsForReference,
+ /// \brief Reference initialized from a parenthesized initializer list.
+ FK_ParenthesizedListInitForReference,
/// \brief Array must be initialized with an initializer list.
FK_ArrayNeedsInitList,
/// \brief Array must be initialized with an initializer list or a
@@ -853,6 +877,8 @@ public:
FK_ConversionFromPropertyFailed,
/// \brief Too many initializers for scalar
FK_TooManyInitsForScalar,
+ /// \brief Scalar initialized from a parenthesized initializer list.
+ FK_ParenthesizedListInitForScalar,
/// \brief Reference initialization from an initializer list
FK_ReferenceBindingToInitList,
/// \brief Initialization of some unused destination type with an
@@ -879,7 +905,7 @@ public:
/// having its address taken.
FK_AddressOfUnaddressableFunction,
/// \brief List-copy-initialization chose an explicit constructor.
- FK_ExplicitConstructor
+ FK_ExplicitConstructor,
};
private:
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 2ed9548b5936..9134ddf9198c 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -146,7 +146,7 @@ public:
}
// TODO: consider whether this constructor should be restricted to take
- // as input a const IndentifierInfo* (instead of Name),
+ // as input a const IdentifierInfo* (instead of Name),
// forcing other cases towards the constructor taking a DNInfo.
LookupResult(Sema &SemaRef, DeclarationName Name,
SourceLocation NameLoc, Sema::LookupNameKind LookupKind,
diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h
index 37157204ea10..1d681a00552f 100644
--- a/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -90,6 +90,8 @@ public:
/// initializers themselves.
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
+ ExtKind hasExternalDefinitions(const Decl *D) override;
+
/// \brief Find all declarations with the given name in the
/// given context.
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 5220d9873022..941b772b7880 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -98,6 +98,7 @@ namespace clang {
ICR_Exact_Match = 0, ///< Exact Match
ICR_Promotion, ///< Promotion
ICR_Conversion, ///< Conversion
+ ICR_OCL_Scalar_Widening, ///< OpenCL Scalar Widening
ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion
ICR_Writeback_Conversion, ///< ObjC ARC writeback conversion
ICR_C_Conversion, ///< Conversion only allowed in the C standard.
diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h
index fd46de870fb4..848837a1decc 100644
--- a/include/clang/Sema/Ownership.h
+++ b/include/clang/Sema/Ownership.h
@@ -257,6 +257,7 @@ namespace clang {
typedef ActionResult<Decl*> DeclResult;
typedef OpaquePtr<TemplateName> ParsedTemplateTy;
+ typedef UnionOpaquePtr<TemplateName> UnionParsedTemplateTy;
typedef MutableArrayRef<Expr*> MultiExprArg;
typedef MutableArrayRef<Stmt*> MultiStmtArg;
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 4b54807ab660..4487c7c2ccb6 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSwitch.h"
#include <algorithm>
namespace clang {
@@ -135,6 +136,18 @@ public:
/// false if there is an invocation of an initializer on 'self'.
bool ObjCWarnForNoInitDelegation : 1;
+ /// \brief True only when this function has not already built, or attempted
+ /// to build, the initial and final coroutine suspend points
+ bool NeedsCoroutineSuspends : 1;
+
+ /// \brief An enumeration represeting the kind of the first coroutine statement
+ /// in the function. One of co_return, co_await, or co_yield.
+ unsigned char FirstCoroutineStmtKind : 2;
+
+ /// First coroutine statement in the current function.
+ /// (ex co_return, co_await, co_yield)
+ SourceLocation FirstCoroutineStmtLoc;
+
/// First 'return' statement in the current function.
SourceLocation FirstReturnLoc;
@@ -157,12 +170,10 @@ public:
SmallVector<ReturnStmt*, 4> Returns;
/// \brief The promise object for this coroutine, if any.
- VarDecl *CoroutinePromise;
+ VarDecl *CoroutinePromise = nullptr;
- /// \brief The list of coroutine control flow constructs (co_await, co_yield,
- /// co_return) that occur within the function or block. Empty if and only if
- /// this function or block is not (yet known to be) a coroutine.
- SmallVector<Stmt*, 4> CoroutineStmts;
+ /// \brief The initial and final coroutine suspend points.
+ std::pair<Stmt *, Stmt *> CoroutineSuspends;
/// \brief The stack of currently active compound stamement scopes in the
/// function.
@@ -376,7 +387,47 @@ public:
(HasIndirectGoto ||
(HasBranchProtectedScope && HasBranchIntoScope));
}
-
+
+ void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) {
+ assert(FirstCoroutineStmtLoc.isInvalid() &&
+ "first coroutine statement location already set");
+ FirstCoroutineStmtLoc = Loc;
+ FirstCoroutineStmtKind = llvm::StringSwitch<unsigned char>(Keyword)
+ .Case("co_return", 0)
+ .Case("co_await", 1)
+ .Case("co_yield", 2);
+ }
+
+ StringRef getFirstCoroutineStmtKeyword() const {
+ assert(FirstCoroutineStmtLoc.isValid()
+ && "no coroutine statement available");
+ switch (FirstCoroutineStmtKind) {
+ case 0: return "co_return";
+ case 1: return "co_await";
+ case 2: return "co_yield";
+ default:
+ llvm_unreachable("FirstCoroutineStmtKind has an invalid value");
+ };
+ }
+
+ void setNeedsCoroutineSuspends(bool value = true) {
+ assert((!value || CoroutineSuspends.first == nullptr) &&
+ "we already have valid suspend points");
+ NeedsCoroutineSuspends = value;
+ }
+
+ bool hasInvalidCoroutineSuspends() const {
+ return !NeedsCoroutineSuspends && CoroutineSuspends.first == nullptr;
+ }
+
+ void setCoroutineSuspends(Stmt *Initial, Stmt *Final) {
+ assert(Initial && Final && "suspend points cannot be null");
+ assert(CoroutineSuspends.first == nullptr && "suspend points already set");
+ NeedsCoroutineSuspends = false;
+ CoroutineSuspends.first = Initial;
+ CoroutineSuspends.second = Final;
+ }
+
FunctionScopeInfo(DiagnosticsEngine &Diag)
: Kind(SK_Function),
HasBranchProtectedScope(false),
@@ -391,6 +442,7 @@ public:
ObjCWarnForNoDesignatedInitChain(false),
ObjCIsSecondaryInit(false),
ObjCWarnForNoInitDelegation(false),
+ NeedsCoroutineSuspends(true),
ErrorTrap(Diag) { }
virtual ~FunctionScopeInfo();
@@ -452,6 +504,14 @@ public:
/// non-static data member that would hold the capture.
QualType CaptureType;
+ /// \brief Whether an explicit capture has been odr-used in the body of the
+ /// lambda.
+ bool ODRUsed;
+
+ /// \brief Whether an explicit capture has been non-odr-used in the body of
+ /// the lambda.
+ bool NonODRUsed;
+
public:
Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
SourceLocation Loc, SourceLocation EllipsisLoc,
@@ -460,7 +520,8 @@ public:
InitExprAndCaptureKind(
Cpy, !Var ? Cap_VLA : Block ? Cap_Block : ByRef ? Cap_ByRef
: Cap_ByCopy),
- Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}
+ Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType),
+ ODRUsed(false), NonODRUsed(false) {}
enum IsThisCapture { ThisCapture };
Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
@@ -468,7 +529,8 @@ public:
: VarAndNestedAndThis(
nullptr, (IsThisCaptured | (IsNested ? IsNestedCapture : 0))),
InitExprAndCaptureKind(Cpy, ByCopy ? Cap_ByCopy : Cap_ByRef),
- Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}
+ Loc(Loc), EllipsisLoc(), CaptureType(CaptureType), ODRUsed(false),
+ NonODRUsed(false) {}
bool isThisCapture() const {
return VarAndNestedAndThis.getInt() & IsThisCaptured;
@@ -491,6 +553,9 @@ public:
bool isNested() const {
return VarAndNestedAndThis.getInt() & IsNestedCapture;
}
+ bool isODRUsed() const { return ODRUsed; }
+ bool isNonODRUsed() const { return NonODRUsed; }
+ void markUsed(bool IsODRUse) { (IsODRUse ? ODRUsed : NonODRUsed) = true; }
VarDecl *getVariable() const {
return VarAndNestedAndThis.getPointer();
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 63d078498fe4..5a3cdfb77c9c 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -26,6 +26,7 @@
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/NSAPI.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/ExpressionTraits.h"
@@ -101,6 +102,7 @@ namespace clang {
class CodeCompletionAllocator;
class CodeCompletionTUInfo;
class CodeCompletionResult;
+ class CoroutineBodyStmt;
class Decl;
class DeclAccessPair;
class DeclContext;
@@ -679,7 +681,8 @@ public:
: S(S), SavedContext(S, DC)
{
S.PushFunctionScope();
- S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ S.PushExpressionEvaluationContext(
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
}
~SynthesizedFunctionScope() {
@@ -800,7 +803,7 @@ public:
/// \brief Describes how the expressions currently being parsed are
/// evaluated at run-time, if at all.
- enum ExpressionEvaluationContext {
+ enum class ExpressionEvaluationContext {
/// \brief The current expression and its subexpressions occur within an
/// unevaluated operand (C++11 [expr]p7), such as the subexpression of
/// \c sizeof, where the type of the expression may be significant but
@@ -906,8 +909,12 @@ public:
MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx);
bool isUnevaluated() const {
- return Context == Unevaluated || Context == UnevaluatedAbstract ||
- Context == UnevaluatedList;
+ return Context == ExpressionEvaluationContext::Unevaluated ||
+ Context == ExpressionEvaluationContext::UnevaluatedAbstract ||
+ Context == ExpressionEvaluationContext::UnevaluatedList;
+ }
+ bool isConstantEvaluated() const {
+ return Context == ExpressionEvaluationContext::ConstantEvaluated;
}
};
@@ -931,7 +938,7 @@ public:
///
/// This is basically a wrapper around PointerIntPair. The lowest bits of the
/// integer are used to determine whether overload resolution succeeded.
- class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode {
+ class SpecialMemberOverloadResult {
public:
enum Kind {
NoMemberOrDeleted,
@@ -943,9 +950,9 @@ public:
llvm::PointerIntPair<CXXMethodDecl*, 2> Pair;
public:
- SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID)
- : FastFoldingSetNode(ID)
- {}
+ SpecialMemberOverloadResult() : Pair() {}
+ SpecialMemberOverloadResult(CXXMethodDecl *MD)
+ : Pair(MD, MD->isDeleted() ? NoMemberOrDeleted : Success) {}
CXXMethodDecl *getMethod() const { return Pair.getPointer(); }
void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); }
@@ -954,9 +961,18 @@ public:
void setKind(Kind K) { Pair.setInt(K); }
};
+ class SpecialMemberOverloadResultEntry
+ : public llvm::FastFoldingSetNode,
+ public SpecialMemberOverloadResult {
+ public:
+ SpecialMemberOverloadResultEntry(const llvm::FoldingSetNodeID &ID)
+ : FastFoldingSetNode(ID)
+ {}
+ };
+
/// \brief A cache of special member function overload resolution results
/// for C++ records.
- llvm::FoldingSet<SpecialMemberOverloadResult> SpecialMemberCache;
+ llvm::FoldingSet<SpecialMemberOverloadResultEntry> SpecialMemberCache;
/// \brief A cache of the flags available in enumerations with the flag_bits
/// attribute.
@@ -1054,14 +1070,12 @@ public:
/// statements.
class FPContractStateRAII {
public:
- FPContractStateRAII(Sema& S)
- : S(S), OldFPContractState(S.FPFeatures.fp_contract) {}
- ~FPContractStateRAII() {
- S.FPFeatures.fp_contract = OldFPContractState;
- }
+ FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {}
+ ~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; }
+
private:
Sema& S;
- bool OldFPContractState : 1;
+ FPOptions OldFPFeaturesState;
};
void addImplicitTypedef(StringRef Name, QualType T);
@@ -1235,9 +1249,11 @@ public:
sema::BlockScopeInfo *getCurBlock();
/// Retrieve the current lambda scope info, if any.
- /// \param IgnoreCapturedRegions true if should find the top-most lambda scope
- /// info ignoring all inner captured regions scope infos.
- sema::LambdaScopeInfo *getCurLambda(bool IgnoreCapturedRegions = false);
+ /// \param IgnoreNonLambdaCapturingScope true if should find the top-most
+ /// lambda scope info ignoring all inner capturing scopes that are not
+ /// lambda scopes.
+ sema::LambdaScopeInfo *
+ getCurLambda(bool IgnoreNonLambdaCapturingScope = false);
/// \brief Retrieve the current generic lambda info, if any.
sema::LambdaScopeInfo *getCurGenericLambda();
@@ -1548,6 +1564,7 @@ public:
ParsedType ObjectType = nullptr,
bool IsCtorOrDtorName = false,
bool WantNontrivialTypeSourceInfo = false,
+ bool IsClassTemplateDeductionContext = true,
IdentifierInfo **CorrectedII = nullptr);
TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S);
bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S);
@@ -1689,6 +1706,18 @@ public:
bool IsAddressOfOperand,
std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr);
+ /// Describes the detailed kind of a template name. Used in diagnostics.
+ enum class TemplateNameKindForDiagnostics {
+ ClassTemplate,
+ FunctionTemplate,
+ VarTemplate,
+ AliasTemplate,
+ TemplateTemplateParam,
+ DependentTemplate
+ };
+ TemplateNameKindForDiagnostics
+ getTemplateNameKindForDiagnostics(TemplateName Name);
+
Decl *ActOnDeclarator(Scope *S, Declarator &D);
NamedDecl *HandleDeclarator(Scope *S, Declarator &D,
@@ -1709,8 +1738,11 @@ public:
static bool adjustContextForLocalExternDecl(DeclContext *&DC);
void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
+ NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D,
+ const LookupResult &R);
NamedDecl *getShadowedDeclaration(const VarDecl *D, const LookupResult &R);
- void CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R);
+ void CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
+ const LookupResult &R);
void CheckShadow(Scope *S, VarDecl *D);
/// Warn if 'E', which is an expression that is about to be modified, refers
@@ -1747,6 +1779,8 @@ public:
// Returns true if the variable declaration is a redeclaration
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckVariableDeclarationType(VarDecl *NewVD);
+ bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
+ Expr *Init);
void CheckCompleteVariableDeclaration(VarDecl *VD);
void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
@@ -1769,7 +1803,7 @@ public:
// Returns true if the function declaration is a redeclaration
bool CheckFunctionDeclaration(Scope *S,
FunctionDecl *NewFD, LookupResult &Previous,
- bool IsExplicitSpecialization);
+ bool IsMemberSpecialization);
bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl);
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
@@ -1794,7 +1828,6 @@ public:
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit);
void ActOnUninitializedDecl(Decl *dcl);
void ActOnInitializerError(Decl *Dcl);
- bool canInitializeWithParenthesizedList(QualType TargetType);
void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc);
void ActOnCXXForRangeDecl(Decl *D);
@@ -2876,13 +2909,13 @@ public:
LOLR_StringTemplate
};
- SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D,
- CXXSpecialMember SM,
- bool ConstArg,
- bool VolatileArg,
- bool RValueThis,
- bool ConstThis,
- bool VolatileThis);
+ SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D,
+ CXXSpecialMember SM,
+ bool ConstArg,
+ bool VolatileArg,
+ bool RValueThis,
+ bool ConstThis,
+ bool VolatileThis);
typedef std::function<void(const TypoCorrection &)> TypoDiagnosticGenerator;
typedef std::function<ExprResult(Sema &, TypoExpr *, TypoCorrection)>
@@ -2963,9 +2996,6 @@ public:
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
UnresolvedSetImpl &Functions);
- void addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions,
- DeclAccessPair Operator,
- QualType T1, QualType T2);
LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc,
SourceLocation GnuLabelLoc = SourceLocation());
@@ -3098,6 +3128,8 @@ public:
void ProcessPragmaWeak(Scope *S, Decl *D);
// Decl attributes - this routine is the top level dispatcher.
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
+ // Helper for delayed proccessing of attributes.
+ void ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL,
bool IncludeCXX11Attributes = true);
bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
@@ -3184,7 +3216,6 @@ public:
bool IsProtocolMethodDecl);
typedef llvm::SmallPtrSet<Selector, 8> SelectorSet;
- typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap;
/// CheckImplementationIvars - This routine checks if the instance variables
/// listed in the implelementation match those listed in the interface.
@@ -3237,7 +3268,9 @@ public:
SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
+ SourceLocation GetterNameLoc,
Selector SetterSel,
+ SourceLocation SetterNameLoc,
const bool isReadWrite,
unsigned &Attributes,
const unsigned AttributesAsWritten,
@@ -3253,7 +3286,9 @@ public:
SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
+ SourceLocation GetterNameLoc,
Selector SetterSel,
+ SourceLocation SetterNameLoc,
const bool isReadWrite,
const unsigned Attributes,
const unsigned AttributesAsWritten,
@@ -4328,7 +4363,7 @@ public:
/// \brief Determine whether Ctor is an initializer-list constructor, as
/// defined in [dcl.init.list]p2.
- bool isInitListConstructor(const CXXConstructorDecl *Ctor);
+ bool isInitListConstructor(const FunctionDecl *Ctor);
Decl *ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
@@ -4737,7 +4772,8 @@ public:
ParsedType ObjectType,
bool EnteringContext);
- ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType);
+ ParsedType getDestructorTypeForDecltype(const DeclSpec &DS,
+ ParsedType ObjectType);
// Checks that reinterpret casts don't have undefined behavior.
void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
@@ -4953,7 +4989,7 @@ public:
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc);
- /// ActOnArrayTypeTrait - Parsed one of the bianry type trait support
+ /// ActOnArrayTypeTrait - Parsed one of the binary type trait support
/// pseudo-functions.
ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT,
SourceLocation KWLoc,
@@ -5106,7 +5142,8 @@ public:
CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon = nullptr);
+ bool *IsCorrectedToColon = nullptr,
+ bool OnlyNamespace = false);
/// \brief The parser has parsed a nested-name-specifier 'identifier::'.
///
@@ -5130,13 +5167,16 @@ public:
/// are allowed. The bool value pointed by this parameter is set to 'true'
/// if the identifier is treated as if it was followed by ':', not '::'.
///
+ /// \param OnlyNamespace If true, only considers namespaces in lookup.
+ ///
/// \returns true if an error occurred, false otherwise.
bool ActOnCXXNestedNameSpecifier(Scope *S,
NestedNameSpecInfo &IdInfo,
bool EnteringContext,
CXXScopeSpec &SS,
bool ErrorRecoveryLookup = false,
- bool *IsCorrectedToColon = nullptr);
+ bool *IsCorrectedToColon = nullptr,
+ bool OnlyNamespace = false);
ExprResult ActOnDecltypeExpression(Expr *E);
@@ -5312,6 +5352,12 @@ public:
ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope);
+ /// \brief Does copying/destroying the captured variable have side effects?
+ bool CaptureHasSideEffects(const sema::LambdaScopeInfo::Capture &From);
+
+ /// \brief Diagnose if an explicit lambda capture is unused.
+ void DiagnoseUnusedLambdaCapture(const sema::LambdaScopeInfo::Capture &From);
+
/// \brief Complete a lambda-expression having processed and attached the
/// lambda body.
ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
@@ -5604,6 +5650,9 @@ public:
void CheckConversionDeclarator(Declarator &D, QualType &R,
StorageClass& SC);
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
+ void CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
+ StorageClass &SC);
+ void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD);
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD,
@@ -5807,6 +5856,12 @@ public:
TemplateTy &Template,
bool &MemberOfUnknownSpecialization);
+ /// Determine whether a particular identifier might be the name in a C++1z
+ /// deduction-guide declaration.
+ bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
+ SourceLocation NameLoc,
+ ParsedTemplateTy *Template = nullptr);
+
bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
@@ -5882,7 +5937,7 @@ public:
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists,
- bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid);
+ bool IsFriend, bool &IsMemberSpecialization, bool &Invalid);
DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, CXXScopeSpec &SS,
@@ -5911,11 +5966,13 @@ public:
TypeResult
ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- TemplateTy Template, SourceLocation TemplateLoc,
+ TemplateTy Template, IdentifierInfo *TemplateII,
+ SourceLocation TemplateIILoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation RAngleLoc,
- bool IsCtorOrDtorName = false);
+ bool IsCtorOrDtorName = false,
+ bool IsClassName = false);
/// \brief Parsed an elaborated-type-specifier that refers to a template-id,
/// such as \c class T::template apply<U>.
@@ -5957,13 +6014,10 @@ public:
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs);
- TemplateNameKind ActOnDependentTemplateName(Scope *S,
- CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- UnqualifiedId &Name,
- ParsedType ObjectType,
- bool EnteringContext,
- TemplateTy &Template);
+ TemplateNameKind ActOnDependentTemplateName(
+ Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext,
+ TemplateTy &Template, bool AllowInjectedClassName = false);
DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
@@ -6088,12 +6142,17 @@ public:
/// \param Converted Will receive the converted, canonicalized template
/// arguments.
///
+ /// \param UpdateArgsWithConversions If \c true, update \p TemplateArgs to
+ /// contain the converted forms of the template arguments as written.
+ /// Otherwise, \p TemplateArgs will not be modified.
+ ///
/// \returns true if an error occurred, false otherwise.
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted);
+ SmallVectorImpl<TemplateArgument> &Converted,
+ bool UpdateArgsWithConversions = true);
bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
TemplateArgumentLoc &Arg,
@@ -6182,7 +6241,8 @@ public:
/// \param SS the nested-name-specifier following the typename (e.g., 'T::').
/// \param TemplateLoc the location of the 'template' keyword, if any.
/// \param TemplateName The template name.
- /// \param TemplateNameLoc The location of the template name.
+ /// \param TemplateII The identifier used to name the template.
+ /// \param TemplateIILoc The location of the template name.
/// \param LAngleLoc The location of the opening angle bracket ('<').
/// \param TemplateArgs The template arguments.
/// \param RAngleLoc The location of the closing angle bracket ('>').
@@ -6191,7 +6251,8 @@ public:
const CXXScopeSpec &SS,
SourceLocation TemplateLoc,
TemplateTy TemplateName,
- SourceLocation TemplateNameLoc,
+ IdentifierInfo *TemplateII,
+ SourceLocation TemplateIILoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation RAngleLoc);
@@ -6706,6 +6767,9 @@ public:
/// \brief Substitute Replacement for auto in TypeWithAuto
TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType Replacement);
+ /// \brief Completely replace the \c auto in \p TypeWithAuto by
+ /// \p Replacement. This does not retain any \c auto type sugar.
+ QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement);
/// \brief Result type of DeduceAutoType.
enum DeduceAutoResult {
@@ -6724,6 +6788,15 @@ public:
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
+ /// \brief Declare implicit deduction guides for a class template if we've
+ /// not already done so.
+ void DeclareImplicitDeductionGuides(TemplateDecl *Template,
+ SourceLocation Loc);
+
+ QualType DeduceTemplateSpecializationFromInitializer(
+ TypeSourceInfo *TInfo, const InitializedEntity &Entity,
+ const InitializationKind &Kind, MultiExprArg Init);
+
QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
QualType Type, TypeSourceInfo *TSI,
SourceRange Range, bool DirectInit,
@@ -6792,10 +6865,12 @@ public:
bool RelativeToPrimary = false,
const FunctionDecl *Pattern = nullptr);
- /// \brief A template instantiation that is currently in progress.
- struct ActiveTemplateInstantiation {
+ /// A context in which code is being synthesized (where a source location
+ /// alone is not sufficient to identify the context). This covers template
+ /// instantiation and various forms of implicitly-generated functions.
+ struct CodeSynthesisContext {
/// \brief The kind of template instantiation we are performing
- enum InstantiationKind {
+ enum SynthesisKind {
/// We are instantiating a template declaration. The entity is
/// the declaration we're instantiating (e.g., a CXXRecordDecl).
TemplateInstantiation,
@@ -6834,28 +6909,42 @@ public:
/// We are instantiating the exception specification for a function
/// template which was deferred until it was needed.
- ExceptionSpecInstantiation
+ ExceptionSpecInstantiation,
+
+ /// We are declaring an implicit special member function.
+ DeclaringSpecialMember,
} Kind;
- /// \brief The point of instantiation within the source code.
+ /// \brief Was the enclosing context a non-instantiation SFINAE context?
+ bool SavedInNonInstantiationSFINAEContext;
+
+ /// \brief The point of instantiation or synthesis within the source code.
SourceLocation PointOfInstantiation;
+ /// \brief The entity that is being synthesized.
+ Decl *Entity;
+
/// \brief The template (or partial specialization) in which we are
/// performing the instantiation, for substitutions of prior template
/// arguments.
NamedDecl *Template;
- /// \brief The entity that is being instantiated.
- Decl *Entity;
-
/// \brief The list of template arguments we are substituting, if they
/// are not part of the entity.
const TemplateArgument *TemplateArgs;
- /// \brief The number of template arguments in TemplateArgs.
- unsigned NumTemplateArgs;
+ // FIXME: Wrap this union around more members, or perhaps store the
+ // kind-specific members in the RAII object owning the context.
+ union {
+ /// \brief The number of template arguments in TemplateArgs.
+ unsigned NumTemplateArgs;
+
+ /// \brief The special member being declared or defined.
+ CXXSpecialMember SpecialMember;
+ };
ArrayRef<TemplateArgument> template_arguments() const {
+ assert(Kind != DeclaringSpecialMember);
return {TemplateArgs, NumTemplateArgs};
}
@@ -6868,56 +6957,20 @@ public:
/// template instantiation.
SourceRange InstantiationRange;
- ActiveTemplateInstantiation()
- : Kind(TemplateInstantiation), Template(nullptr), Entity(nullptr),
+ CodeSynthesisContext()
+ : Kind(TemplateInstantiation), Entity(nullptr), Template(nullptr),
TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {}
/// \brief Determines whether this template is an actual instantiation
/// that should be counted toward the maximum instantiation depth.
bool isInstantiationRecord() const;
-
- friend bool operator==(const ActiveTemplateInstantiation &X,
- const ActiveTemplateInstantiation &Y) {
- if (X.Kind != Y.Kind)
- return false;
-
- if (X.Entity != Y.Entity)
- return false;
-
- switch (X.Kind) {
- case TemplateInstantiation:
- case ExceptionSpecInstantiation:
- return true;
-
- case PriorTemplateArgumentSubstitution:
- case DefaultTemplateArgumentChecking:
- return X.Template == Y.Template && X.TemplateArgs == Y.TemplateArgs;
-
- case DefaultTemplateArgumentInstantiation:
- case ExplicitTemplateArgumentSubstitution:
- case DeducedTemplateArgumentSubstitution:
- case DefaultFunctionArgumentInstantiation:
- return X.TemplateArgs == Y.TemplateArgs;
-
- }
-
- llvm_unreachable("Invalid InstantiationKind!");
- }
-
- friend bool operator!=(const ActiveTemplateInstantiation &X,
- const ActiveTemplateInstantiation &Y) {
- return !(X == Y);
- }
};
- /// \brief List of active template instantiations.
+ /// \brief List of active code synthesis contexts.
///
- /// This vector is treated as a stack. As one template instantiation
- /// requires another template instantiation, additional
- /// instantiations are pushed onto the stack up to a
- /// user-configurable limit LangOptions::InstantiationDepth.
- SmallVector<ActiveTemplateInstantiation, 16>
- ActiveTemplateInstantiations;
+ /// This vector is treated as a stack. As synthesis of one entity requires
+ /// synthesis of another, additional contexts are pushed onto the stack.
+ SmallVector<CodeSynthesisContext, 16> CodeSynthesisContexts;
/// Specializations whose definitions are currently being instantiated.
llvm::DenseSet<std::pair<Decl *, unsigned>> InstantiatingSpecializations;
@@ -6928,7 +6981,7 @@ public:
/// \brief Extra modules inspected when performing a lookup during a template
/// instantiation. Computed lazily.
- SmallVector<Module*, 16> ActiveTemplateInstantiationLookupModules;
+ SmallVector<Module*, 16> CodeSynthesisContextLookupModules;
/// \brief Cache of additional modules that should be used for name lookup
/// within the current template instantiation. Computed lazily; use
@@ -6951,19 +7004,22 @@ public:
/// of a template instantiation or template argument deduction.
bool InNonInstantiationSFINAEContext;
- /// \brief The number of ActiveTemplateInstantiation entries in
- /// \c ActiveTemplateInstantiations that are not actual instantiations and,
- /// therefore, should not be counted as part of the instantiation depth.
+ /// \brief The number of \p CodeSynthesisContexts that are not template
+ /// instantiations and, therefore, should not be counted as part of the
+ /// instantiation depth.
+ ///
+ /// When the instantiation depth reaches the user-configurable limit
+ /// \p LangOptions::InstantiationDepth we will abort instantiation.
+ // FIXME: Should we have a similar limit for other forms of synthesis?
unsigned NonInstantiationEntries;
- /// \brief The last template from which a template instantiation
+ /// \brief The depth of the context stack at the point when the most recent
/// error or warning was produced.
///
- /// This value is used to suppress printing of redundant template
- /// instantiation backtraces when there are multiple errors in the
- /// same instantiation. FIXME: Does this belong in Sema? It's tough
- /// to implement it anywhere else.
- ActiveTemplateInstantiation LastTemplateInstantiationErrorContext;
+ /// This value is used to suppress printing of redundant context stacks
+ /// when there are multiple errors or warnings in the same instantiation.
+ // FIXME: Does this belong in Sema? It's tough to implement it anywhere else.
+ unsigned LastEmittedCodeSynthesisContextDepth = 0;
/// \brief The current index into pack expansion arguments that will be
/// used for substitution of parameter packs.
@@ -7041,7 +7097,7 @@ public:
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
FunctionTemplateDecl *FunctionTemplate,
ArrayRef<TemplateArgument> TemplateArgs,
- ActiveTemplateInstantiation::InstantiationKind Kind,
+ CodeSynthesisContext::SynthesisKind Kind,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange = SourceRange());
@@ -7120,12 +7176,11 @@ public:
Sema &SemaRef;
bool Invalid;
bool AlreadyInstantiating;
- bool SavedInNonInstantiationSFINAEContext;
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
SourceRange InstantiationRange);
InstantiatingTemplate(
- Sema &SemaRef, ActiveTemplateInstantiation::InstantiationKind Kind,
+ Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind,
SourceLocation PointOfInstantiation, SourceRange InstantiationRange,
Decl *Entity, NamedDecl *Template = nullptr,
ArrayRef<TemplateArgument> TemplateArgs = None,
@@ -7137,6 +7192,21 @@ public:
operator=(const InstantiatingTemplate&) = delete;
};
+ void pushCodeSynthesisContext(CodeSynthesisContext Ctx);
+ void popCodeSynthesisContext();
+
+ /// Determine whether we are currently performing template instantiation.
+ bool inTemplateInstantiation() const {
+ return CodeSynthesisContexts.size() > NonInstantiationEntries;
+ }
+
+ void PrintContextStack() {
+ if (!CodeSynthesisContexts.empty() &&
+ CodeSynthesisContexts.size() != LastEmittedCodeSynthesisContextDepth) {
+ PrintInstantiationStack();
+ LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size();
+ }
+ }
void PrintInstantiationStack();
/// \brief Determines whether we are currently in a context where
@@ -7339,7 +7409,8 @@ public:
TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity);
+ SourceLocation Loc, DeclarationName Entity,
+ bool AllowDeducedTST = false);
QualType SubstType(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -7436,6 +7507,12 @@ public:
LateInstantiatedAttrVec *LateAttrs = nullptr,
LocalInstantiationScope *OuterMostScope = nullptr);
+ void
+ InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs,
+ const Decl *Pattern, Decl *Inst,
+ LateInstantiatedAttrVec *LateAttrs = nullptr,
+ LocalInstantiationScope *OuterMostScope = nullptr);
+
bool
InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
@@ -7597,7 +7674,8 @@ public:
Decl * const *ProtoRefs,
unsigned NumProtoRefs,
const SourceLocation *ProtoLocs,
- SourceLocation EndProtoLoc);
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList);
Decl *ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
@@ -8039,8 +8117,9 @@ public:
SourceLocation AliasNameLoc);
/// ActOnPragmaFPContract - Called on well formed
- /// \#pragma {STDC,OPENCL} FP_CONTRACT
- void ActOnPragmaFPContract(tok::OnOffSwitch OOS);
+ /// \#pragma {STDC,OPENCL} FP_CONTRACT and
+ /// \#pragma clang fp contract
+ void ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC);
/// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to
/// a the record decl, to handle '\#pragma pack' and '\#pragma options align'.
@@ -8103,6 +8182,11 @@ public:
void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE,
unsigned SpellingListIndex);
+ /// AddAllocAlignAttr - Adds an alloc_align attribute to a particular
+ /// declaration.
+ void AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
+ unsigned SpellingListIndex);
+
/// AddAlignValueAttr - Adds an align_value attribute to a particular
/// declaration.
void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
@@ -8129,12 +8213,17 @@ public:
//
ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E);
ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E);
- StmtResult ActOnCoreturnStmt(SourceLocation KwLoc, Expr *E);
+ StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E);
- ExprResult BuildCoawaitExpr(SourceLocation KwLoc, Expr *E);
+ ExprResult BuildResolvedCoawaitExpr(SourceLocation KwLoc, Expr *E,
+ bool IsImplicit = false);
+ ExprResult BuildUnresolvedCoawaitExpr(SourceLocation KwLoc, Expr *E,
+ UnresolvedLookupExpr* Lookup);
ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E);
- StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E);
-
+ StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E,
+ bool IsImplicit = false);
+ StmtResult BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs);
+ VarDecl *buildCoroutinePromise(SourceLocation Loc);
void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body);
//===--------------------------------------------------------------------===//
@@ -8314,6 +8403,9 @@ public:
return IsInOpenMPDeclareTargetContext;
}
+ /// Return the number of captured regions created for an OpenMP directive.
+ static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind);
+
/// \brief Initialization of captured region for OpenMP region.
void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);
/// \brief End of OpenMP region.
@@ -9257,7 +9349,7 @@ public:
ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr,
CastKind &Kind);
- ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo,
+ ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type,
SourceLocation LParenLoc,
Expr *CastExpr,
SourceLocation RParenLoc);
@@ -9265,14 +9357,14 @@ public:
enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error };
/// \brief Checks for invalid conversions and casts between
- /// retainable pointers and other pointer kinds.
- ARCConversionResult CheckObjCARCConversion(SourceRange castRange,
- QualType castType, Expr *&op,
- CheckedConversionKind CCK,
- bool Diagnose = true,
- bool DiagnoseCFAudited = false,
- BinaryOperatorKind Opc = BO_PtrMemD
- );
+ /// retainable pointers and other pointer kinds for ARC and Weak.
+ ARCConversionResult CheckObjCConversion(SourceRange castRange,
+ QualType castType, Expr *&op,
+ CheckedConversionKind CCK,
+ bool Diagnose = true,
+ bool DiagnoseCFAudited = false,
+ BinaryOperatorKind Opc = BO_PtrMemD
+ );
Expr *stripARCUnbridgedCast(Expr *e);
void diagnoseARCUnbridgedCast(Expr *e);
@@ -9777,6 +9869,8 @@ public:
void CodeCompletePostfixExpression(Scope *S, ExprResult LHS);
void CodeCompleteTag(Scope *S, unsigned TagSpec);
void CodeCompleteTypeQualifiers(DeclSpec &DS);
+ void CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D,
+ const VirtSpecifiers *VS = nullptr);
void CodeCompleteBracketDeclarator(Scope *S);
void CodeCompleteCase(Scope *S);
void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args);
@@ -9922,6 +10016,7 @@ private:
bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall);
+ bool CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall);
bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
@@ -10028,6 +10123,11 @@ private:
void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field,
Expr *Init);
+ /// Check if there is a field shadowing.
+ void CheckShadowInheritedFields(const SourceLocation &Loc,
+ DeclarationName FieldName,
+ const CXXRecordDecl *RD);
+
/// \brief Check if the given expression contains 'break' or 'continue'
/// statement that produces control flow different from GCC.
void CheckBreakContinueBinding(Expr *E);
@@ -10221,6 +10321,7 @@ class EnterExpressionEvaluationContext {
bool Entered = true;
public:
+
EnterExpressionEvaluationContext(Sema &Actions,
Sema::ExpressionEvaluationContext NewContext,
Decl *LambdaContextDecl = nullptr,
@@ -10251,8 +10352,8 @@ public:
// a context.
if (ShouldEnter && Actions.isUnevaluatedContext() &&
Actions.getLangOpts().CPlusPlus11) {
- Actions.PushExpressionEvaluationContext(Sema::UnevaluatedList, nullptr,
- false);
+ Actions.PushExpressionEvaluationContext(
+ Sema::ExpressionEvaluationContext::UnevaluatedList, nullptr, false);
Entered = true;
}
}
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 401bbbf1e566..644d55b93f1b 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -46,6 +46,10 @@ namespace clang {
/// \brief The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
SmallVector<ArgList, 4> TemplateArgumentLists;
+
+ /// \brief The number of outer levels of template arguments that are not
+ /// being substituted.
+ unsigned NumRetainedOuterLevels = 0;
public:
/// \brief Construct an empty set of template argument lists.
@@ -59,11 +63,19 @@ namespace clang {
/// \brief Determine the number of levels in this template argument
/// list.
- unsigned getNumLevels() const { return TemplateArgumentLists.size(); }
-
+ unsigned getNumLevels() const {
+ return TemplateArgumentLists.size() + NumRetainedOuterLevels;
+ }
+
+ /// \brief Determine the number of substituted levels in this template
+ /// argument list.
+ unsigned getNumSubstitutedLevels() const {
+ return TemplateArgumentLists.size();
+ }
+
/// \brief Retrieve the template argument at a given depth and index.
const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
- assert(Depth < TemplateArgumentLists.size());
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
return TemplateArgumentLists[getNumLevels() - Depth - 1][Index];
}
@@ -73,7 +85,10 @@ namespace clang {
///
/// There must exist a template argument list at the given depth.
bool hasTemplateArgument(unsigned Depth, unsigned Index) const {
- assert(Depth < TemplateArgumentLists.size());
+ assert(Depth < getNumLevels());
+
+ if (Depth < NumRetainedOuterLevels)
+ return false;
if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size())
return false;
@@ -84,7 +99,7 @@ namespace clang {
/// \brief Clear out a specific template argument.
void setArgument(unsigned Depth, unsigned Index,
TemplateArgument Arg) {
- assert(Depth < TemplateArgumentLists.size());
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
const_cast<TemplateArgument&>(
TemplateArgumentLists[getNumLevels() - Depth - 1][Index])
@@ -101,9 +116,18 @@ namespace clang {
/// \brief Add a new outmost level to the multi-level template argument
/// list.
void addOuterTemplateArguments(ArgList Args) {
+ assert(!NumRetainedOuterLevels &&
+ "substituted args outside retained args?");
TemplateArgumentLists.push_back(Args);
}
+ /// \brief Add an outermost level that we are not substituting. We have no
+ /// arguments at this level, and do not remove it from the depth of inner
+ /// template parameters that we instantiate.
+ void addOuterRetainedLevel() {
+ ++NumRetainedOuterLevels;
+ }
+
/// \brief Retrieve the innermost template argument list.
const ArgList &getInnermost() const {
return TemplateArgumentLists.front();
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index acbd6d1deb5b..823440b19713 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -226,7 +226,7 @@ namespace clang {
/// \brief The block containing the detailed preprocessing record.
PREPROCESSOR_DETAIL_BLOCK_ID,
-
+
/// \brief The block containing the submodule structure.
SUBMODULE_BLOCK_ID,
@@ -253,6 +253,12 @@ namespace clang {
/// \brief A block containing a module file extension.
EXTENSION_BLOCK_ID,
+
+ /// A block with unhashed content.
+ ///
+ /// These records should not change the \a ASTFileSignature. See \a
+ /// UnhashedControlBlockRecordTypes for the list of records.
+ UNHASHED_CONTROL_BLOCK_ID,
};
/// \brief Record types that occur within the control block.
@@ -288,9 +294,6 @@ namespace clang {
/// AST file.
MODULE_MAP_FILE,
- /// \brief Record code for the signature that identifiers this AST file.
- SIGNATURE,
-
/// \brief Record code for the module build directory.
MODULE_DIRECTORY,
};
@@ -309,9 +312,6 @@ namespace clang {
/// \brief Record code for the target options table.
TARGET_OPTIONS,
- /// \brief Record code for the diagnostic options table.
- DIAGNOSTIC_OPTIONS,
-
/// \brief Record code for the filesystem options table.
FILE_SYSTEM_OPTIONS,
@@ -322,6 +322,18 @@ namespace clang {
PREPROCESSOR_OPTIONS,
};
+ /// Record codes for the unhashed control block.
+ enum UnhashedControlBlockRecordTypes {
+ /// Record code for the signature that identifiers this AST file.
+ SIGNATURE = 1,
+
+ /// Record code for the diagnostic options table.
+ DIAGNOSTIC_OPTIONS,
+
+ /// Record code for \#pragma diagnostic mappings.
+ DIAG_PRAGMA_MAPPINGS,
+ };
+
/// \brief Record code for extension blocks.
enum ExtensionBlockRecordTypes {
/// Metadata describing this particular extension.
@@ -493,8 +505,7 @@ namespace clang {
// ID 31 used to be a list of offsets to DECL_CXX_BASE_SPECIFIERS records.
- /// \brief Record code for \#pragma diagnostic mappings.
- DIAG_PRAGMA_MAPPINGS = 32,
+ // ID 32 used to be the code for \#pragma diagnostic mappings.
/// \brief Record code for special CUDA declarations.
CUDA_SPECIAL_DECL_REFS = 33,
@@ -591,6 +602,11 @@ namespace clang {
/// \brief Record code for declarations associated with OpenCL extensions.
OPENCL_EXTENSION_DECLS = 59,
+
+ MODULAR_CODEGEN_DECLS = 60,
+
+ /// \brief Record code for \#pragma pack options.
+ PACK_PRAGMA_OPTIONS = 61,
};
/// \brief Record types used within a source manager block.
@@ -801,14 +817,12 @@ namespace clang {
PREDEF_TYPE_SAMPLER_ID = 39,
/// \brief OpenCL queue type.
PREDEF_TYPE_QUEUE_ID = 40,
- /// \brief OpenCL ndrange type.
- PREDEF_TYPE_NDRANGE_ID = 41,
/// \brief OpenCL reserve_id type.
- PREDEF_TYPE_RESERVE_ID_ID = 42,
+ PREDEF_TYPE_RESERVE_ID_ID = 41,
/// \brief The placeholder type for OpenMP array section.
- PREDEF_TYPE_OMP_ARRAY_SECTION = 43,
+ PREDEF_TYPE_OMP_ARRAY_SECTION = 42,
/// \brief The '__float128' type
- PREDEF_TYPE_FLOAT128_ID = 44,
+ PREDEF_TYPE_FLOAT128_ID = 43,
/// \brief OpenCL image types with auto numeration
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
PREDEF_TYPE_##Id##_ID,
@@ -914,7 +928,11 @@ namespace clang {
/// \brief A PipeType record.
TYPE_PIPE = 43,
/// \brief An ObjCTypeParamType record.
- TYPE_OBJC_TYPE_PARAM = 44
+ TYPE_OBJC_TYPE_PARAM = 44,
+ /// \brief A DeducedTemplateSpecializationType record.
+ TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45,
+ /// \brief A DependentSizedExtVectorType record.
+ TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46
};
/// \brief The type IDs for special types constructed by semantic
@@ -1121,6 +1139,8 @@ namespace clang {
DECL_EXPORT,
/// \brief A CXXRecordDecl record.
DECL_CXX_RECORD,
+ /// \brief A CXXDeductionGuideDecl record.
+ DECL_CXX_DEDUCTION_GUIDE,
/// \brief A CXXMethodDecl record.
DECL_CXX_METHOD,
/// \brief A CXXConstructorDecl record.
@@ -1624,7 +1644,8 @@ namespace clang {
IdentifierInfo *getIdentifier() const {
assert(Kind == DeclarationName::Identifier ||
- Kind == DeclarationName::CXXLiteralOperatorName);
+ Kind == DeclarationName::CXXLiteralOperatorName ||
+ Kind == DeclarationName::CXXDeductionGuideName);
return (IdentifierInfo *)Data;
}
Selector getSelector() const {
diff --git a/include/clang/Serialization/ASTDeserializationListener.h b/include/clang/Serialization/ASTDeserializationListener.h
index 4b10c39d8fb2..c26f3e0b425e 100644
--- a/include/clang/Serialization/ASTDeserializationListener.h
+++ b/include/clang/Serialization/ASTDeserializationListener.h
@@ -26,6 +26,7 @@ class QualType;
class MacroDefinitionRecord;
class MacroInfo;
class Module;
+class SourceLocation;
class ASTDeserializationListener {
public:
@@ -52,6 +53,9 @@ public:
MacroDefinitionRecord *MD) {}
/// \brief A module definition was read from the AST file.
virtual void ModuleRead(serialization::SubmoduleID ID, Module *Mod) {}
+ /// \brief A module import was read from the AST file.
+ virtual void ModuleImportRead(serialization::SubmoduleID ID,
+ SourceLocation ImportLoc) {}
};
}
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 93994e2c519c..63ccb2461616 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -408,6 +408,9 @@ private:
/// \brief The module manager which manages modules and their dependencies
ModuleManager ModuleMgr;
+ /// The cache that manages memory buffers for PCM files.
+ MemoryBufferCache &PCMCache;
+
/// \brief A dummy identifier resolver used to merge TU-scope declarations in
/// C, for the cases where we don't have a Sema object to provide a real
/// identifier resolver.
@@ -700,7 +703,7 @@ private:
/// \brief Mapping from global preprocessing entity IDs to the module in
/// which the preprocessed entity resides along with the offset that should be
- /// added to the global preprocessing entitiy ID to produce a local ID.
+ /// added to the global preprocessing entity ID to produce a local ID.
GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap;
/// \name CodeGen-relevant special data
@@ -808,6 +811,17 @@ private:
int PragmaMSPointersToMembersState = -1;
SourceLocation PointersToMembersPragmaLocation;
+ /// \brief The pragma pack state.
+ Optional<unsigned> PragmaPackCurrentValue;
+ SourceLocation PragmaPackCurrentLocation;
+ struct PragmaPackStackEntry {
+ unsigned Value;
+ SourceLocation Location;
+ StringRef SlotLabel;
+ };
+ llvm::SmallVector<PragmaPackStackEntry, 2> PragmaPackStack;
+ llvm::SmallVector<std::string, 2> PragmaPackStrings;
+
/// \brief The OpenCL extension settings.
OpenCLOptions OpenCLExtensions;
@@ -970,14 +984,26 @@ private:
/// \brief The generation number of each identifier, which keeps track of
/// the last time we loaded information about this identifier.
llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration;
-
- /// \brief Contains declarations and definitions that will be
+
+ class InterestingDecl {
+ Decl *D;
+ bool DeclHasPendingBody;
+
+ public:
+ InterestingDecl(Decl *D, bool HasBody)
+ : D(D), DeclHasPendingBody(HasBody) {}
+ Decl *getDecl() { return D; }
+ /// Whether the declaration has a pending body.
+ bool hasPendingBody() { return DeclHasPendingBody; }
+ };
+
+ /// \brief Contains declarations and definitions that could be
/// "interesting" to the ASTConsumer, when we get that AST consumer.
///
/// "Interesting" declarations are those that have data that may
/// need to be emitted, such as inline function definitions or
/// Objective-C protocols.
- std::deque<Decl *> InterestingDecls;
+ std::deque<InterestingDecl> PotentiallyInterestingDecls;
/// \brief The list of redeclaration chains that still need to be
/// reconstructed, and the local offset to the corresponding list
@@ -1101,6 +1127,8 @@ private:
/// predefines buffer may contain additional definitions.
std::string SuggestedPredefines;
+ llvm::DenseMap<const Decl *, bool> BodySource;
+
/// \brief Reads a statement from the specified cursor.
Stmt *ReadStmtFromStream(ModuleFile &F);
@@ -1174,7 +1202,7 @@ private:
SourceLocation ImportLoc, ModuleFile *ImportedBy,
SmallVectorImpl<ImportedModule> &Loaded,
off_t ExpectedSize, time_t ExpectedModTime,
- serialization::ASTFileSignature ExpectedSignature,
+ ASTFileSignature ExpectedSignature,
unsigned ClientLoadCapabilities);
ASTReadResult ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
@@ -1183,9 +1211,25 @@ private:
static ASTReadResult ReadOptionsBlock(
llvm::BitstreamCursor &Stream, unsigned ClientLoadCapabilities,
bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener,
- std::string &SuggestedPredefines, bool ValidateDiagnosticOptions);
+ std::string &SuggestedPredefines);
+
+ /// Read the unhashed control block.
+ ///
+ /// This has no effect on \c F.Stream, instead creating a fresh cursor from
+ /// \c F.Data and reading ahead.
+ ASTReadResult readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy,
+ unsigned ClientLoadCapabilities);
+
+ static ASTReadResult
+ readUnhashedControlBlockImpl(ModuleFile *F, llvm::StringRef StreamData,
+ unsigned ClientLoadCapabilities,
+ bool AllowCompatibleConfigurationMismatch,
+ ASTReaderListener *Listener,
+ bool ValidateDiagnosticOptions);
+
ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities);
ASTReadResult ReadExtensionBlock(ModuleFile &F);
+ void ReadModuleOffsetMap(ModuleFile &F) const;
bool ParseLineTable(ModuleFile &F, const RecordData &Record);
bool ReadSourceManagerBlock(ModuleFile &F);
llvm::BitstreamCursor &SLocCursorForID(int ID);
@@ -1268,6 +1312,7 @@ private:
llvm::iterator_range<PreprocessingRecord::iterator>
getModulePreprocessedEntities(ModuleFile &Mod) const;
+public:
class ModuleDeclIterator
: public llvm::iterator_adaptor_base<
ModuleDeclIterator, const serialization::LocalDeclID *,
@@ -1298,6 +1343,7 @@ private:
llvm::iterator_range<ModuleDeclIterator>
getModuleFileLevelDecls(ModuleFile &Mod);
+private:
void PassInterestingDeclsToConsumer();
void PassInterestingDeclToConsumer(Decl *D);
@@ -1318,9 +1364,9 @@ private:
///
/// This routine should only be used for fatal errors that have to
/// do with non-routine failures (e.g., corrupted AST file).
- void Error(StringRef Msg);
+ void Error(StringRef Msg) const;
void Error(unsigned DiagID, StringRef Arg1 = StringRef(),
- StringRef Arg2 = StringRef());
+ StringRef Arg2 = StringRef()) const;
ASTReader(const ASTReader &) = delete;
void operator=(const ASTReader &) = delete;
@@ -1564,7 +1610,7 @@ public:
const LangOptions &LangOpts,
const TargetOptions &TargetOpts,
const PreprocessorOptions &PPOpts,
- std::string ExistingModuleCachePath);
+ StringRef ExistingModuleCachePath);
/// \brief Returns the suggested contents of the predefines buffer,
/// which contains a (typically-empty) subset of the predefines
@@ -1631,11 +1677,8 @@ public:
/// reader.
unsigned getTotalNumPreprocessedEntities() const {
unsigned Result = 0;
- for (ModuleConstIterator I = ModuleMgr.begin(),
- E = ModuleMgr.end(); I != E; ++I) {
- Result += (*I)->NumPreprocessedEntities;
- }
-
+ for (const auto &M : ModuleMgr)
+ Result += M.NumPreprocessedEntities;
return Result;
}
@@ -1904,10 +1947,10 @@ public:
SmallVectorImpl<Decl *> *Decls = nullptr);
/// \brief Report a diagnostic.
- DiagnosticBuilder Diag(unsigned DiagID);
+ DiagnosticBuilder Diag(unsigned DiagID) const;
/// \brief Report a diagnostic.
- DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const;
IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID);
@@ -1968,6 +2011,8 @@ public:
/// \brief Return a descriptor for the corresponding module.
llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
+ ExtKind hasExternalDefinitions(const Decl *D) override;
+
/// \brief Retrieve a selector from the given module with its local ID
/// number.
Selector getLocalSelector(ModuleFile &M, unsigned LocalID);
@@ -2057,6 +2102,8 @@ public:
/// location space into ours.
SourceLocation TranslateSourceLocation(ModuleFile &ModuleFile,
SourceLocation Loc) const {
+ if (!ModuleFile.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(ModuleFile);
assert(ModuleFile.SLocRemap.find(Loc.getOffset()) !=
ModuleFile.SLocRemap.end() &&
"Cannot find offset to remap.");
@@ -2098,8 +2145,7 @@ public:
unsigned &Idx);
/// \brief Reads attributes from the current stream position.
- void ReadAttributes(ModuleFile &F, AttrVec &Attrs,
- const RecordData &Record, unsigned &Idx);
+ void ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs);
/// \brief Reads a statement.
Stmt *ReadStmt(ModuleFile &F);
@@ -2189,6 +2235,12 @@ public:
/// \brief Loads comments ranges.
void ReadComments() override;
+ /// Visit all the input files of the given module file.
+ void visitInputFiles(serialization::ModuleFile &MF,
+ bool IncludeSystem, bool Complain,
+ llvm::function_ref<void(const serialization::InputFile &IF,
+ bool isSystem)> Visitor);
+
bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; }
};
@@ -2284,6 +2336,14 @@ public:
/// \brief Reads a sub-expression operand during statement reading.
Expr *readSubExpr() { return Reader->ReadSubExpr(); }
+ /// \brief Reads a declaration with the given local ID in the given module.
+ ///
+ /// \returns The requested declaration, casted to the given return type.
+ template<typename T>
+ T *GetLocalDeclAs(uint32_t LocalID) {
+ return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID));
+ }
+
/// \brief Reads a TemplateArgumentLocInfo appropriate for the
/// given TemplateArgument kind, advancing Idx.
TemplateArgumentLocInfo
@@ -2455,7 +2515,7 @@ public:
/// \brief Reads attributes from the current stream position, advancing Idx.
void readAttributes(AttrVec &Attrs) {
- return Reader->ReadAttributes(*F, Attrs, Record, Idx);
+ return Reader->ReadAttributes(*this, Attrs);
}
/// \brief Reads a token out of a record, advancing Idx.
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 0d6b0268109d..17cf726e4d6b 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -54,6 +54,7 @@ class MacroInfo;
class OpaqueValueExpr;
class OpenCLOptions;
class ASTReader;
+class MemoryBufferCache;
class Module;
class ModuleFileExtension;
class ModuleFileExtensionWriter;
@@ -106,6 +107,12 @@ private:
/// \brief The bitstream writer used to emit this precompiled header.
llvm::BitstreamWriter &Stream;
+ /// The buffer associated with the bitstream.
+ const SmallVectorImpl<char> &Buffer;
+
+ /// \brief The PCM manager which manages memory buffers for pcm files.
+ MemoryBufferCache &PCMCache;
+
/// \brief The ASTContext we're writing.
ASTContext *Context = nullptr;
@@ -365,6 +372,7 @@ private:
/// IDs, since they will be written out to an EAGERLY_DESERIALIZED_DECLS
/// record.
SmallVector<uint64_t, 16> EagerlyDeserializedDecls;
+ SmallVector<uint64_t, 16> ModularCodegenDecls;
/// \brief DeclContexts that have received extensions since their serialized
/// form.
@@ -424,8 +432,16 @@ private:
void WriteSubStmt(Stmt *S);
void WriteBlockInfoBlock();
- uint64_t WriteControlBlock(Preprocessor &PP, ASTContext &Context,
- StringRef isysroot, const std::string &OutputFile);
+ void WriteControlBlock(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot, const std::string &OutputFile);
+
+ /// Write out the signature and diagnostic options, and return the signature.
+ ASTFileSignature writeUnhashedControlBlock(Preprocessor &PP,
+ ASTContext &Context);
+
+ /// Calculate hash of the pcm content.
+ static ASTFileSignature createSignature(StringRef Bytes);
+
void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts,
bool Modules);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
@@ -469,6 +485,7 @@ private:
void WriteOptimizePragmaOptions(Sema &SemaRef);
void WriteMSStructPragmaOptions(Sema &SemaRef);
void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef);
+ void WritePackPragmaOptions(Sema &SemaRef);
void WriteModuleFileExtension(Sema &SemaRef,
ModuleFileExtensionWriter &Writer);
@@ -492,14 +509,15 @@ private:
void WriteDeclAbbrevs();
void WriteDecl(ASTContext &Context, Decl *D);
- uint64_t WriteASTCore(Sema &SemaRef,
- StringRef isysroot, const std::string &OutputFile,
- Module *WritingModule);
+ ASTFileSignature WriteASTCore(Sema &SemaRef, StringRef isysroot,
+ const std::string &OutputFile,
+ Module *WritingModule);
public:
/// \brief Create a new precompiled header writer that outputs to
/// the given bitstream.
- ASTWriter(llvm::BitstreamWriter &Stream,
+ ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl<char> &Buffer,
+ MemoryBufferCache &PCMCache,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool IncludeTimestamps = true);
~ASTWriter() override;
@@ -525,9 +543,9 @@ public:
///
/// \return the module signature, which eventually will be a hash of
/// the module but currently is merely a random 32-bit number.
- uint64_t WriteAST(Sema &SemaRef, const std::string &OutputFile,
- Module *WritingModule, StringRef isysroot,
- bool hasErrors = false);
+ ASTFileSignature WriteAST(Sema &SemaRef, const std::string &OutputFile,
+ Module *WritingModule, StringRef isysroot,
+ bool hasErrors = false);
/// \brief Emit a token.
void AddToken(const Token &Tok, RecordDataImpl &Record);
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 58b3149d407e..4e4bf44f3492 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_SERIALIZATION_MODULE_H
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ContinuousRangeMap.h"
@@ -89,8 +90,6 @@ public:
bool isNotFound() const { return Val.getInt() == NotFound; }
};
-typedef unsigned ASTFileSignature;
-
/// \brief Information about a module that has been loaded by the ASTReader.
///
/// Each instance of the Module class corresponds to a single AST file, which
@@ -100,13 +99,14 @@ typedef unsigned ASTFileSignature;
/// other modules.
class ModuleFile {
public:
- ModuleFile(ModuleKind Kind, unsigned Generation);
+ ModuleFile(ModuleKind Kind, unsigned Generation)
+ : Kind(Kind), Generation(Generation) {}
~ModuleFile();
// === General information ===
/// \brief The index of this module in the list of modules.
- unsigned Index;
+ unsigned Index = 0;
/// \brief The type of this module.
ModuleKind Kind;
@@ -144,34 +144,34 @@ public:
std::string ModuleMapPath;
/// \brief Whether this precompiled header is a relocatable PCH file.
- bool RelocatablePCH;
+ bool RelocatablePCH = false;
/// \brief Whether timestamps are included in this module file.
- bool HasTimestamps;
+ bool HasTimestamps = false;
/// \brief The file entry for the module file.
- const FileEntry *File;
+ const FileEntry *File = nullptr;
- /// \brief The signature of the module file, which may be used along with size
+ /// The signature of the module file, which may be used instead of the size
/// and modification time to identify this particular file.
ASTFileSignature Signature;
/// \brief Whether this module has been directly imported by the
/// user.
- bool DirectlyImported;
+ bool DirectlyImported = false;
/// \brief The generation of which this module file is a part.
unsigned Generation;
- /// \brief The memory buffer that stores the data associated with
- /// this AST file.
- std::unique_ptr<llvm::MemoryBuffer> Buffer;
+ /// The memory buffer that stores the data associated with
+ /// this AST file, owned by the PCMCache in the ModuleManager.
+ llvm::MemoryBuffer *Buffer;
/// \brief The size of this file, in bits.
- uint64_t SizeInBits;
+ uint64_t SizeInBits = 0;
/// \brief The global bit offset (or base) of this module
- uint64_t GlobalBitOffset;
+ uint64_t GlobalBitOffset = 0;
/// \brief The serialized bitstream data for this file.
StringRef Data;
@@ -200,21 +200,29 @@ public:
/// file.
std::vector<std::unique_ptr<ModuleFileExtensionReader>> ExtensionReaders;
+ /// The module offset map data for this file. If non-empty, the various
+ /// ContinuousRangeMaps described below have not yet been populated.
+ StringRef ModuleOffsetMap;
+
// === Input Files ===
/// \brief The cursor to the start of the input-files block.
llvm::BitstreamCursor InputFilesCursor;
/// \brief Offsets for all of the input file entries in the AST file.
- const llvm::support::unaligned_uint64_t *InputFileOffsets;
+ const llvm::support::unaligned_uint64_t *InputFileOffsets = nullptr;
/// \brief The input files that have been loaded from this AST file.
std::vector<InputFile> InputFilesLoaded;
+ // All user input files reside at the index range [0, NumUserInputFiles), and
+ // system input files reside at [NumUserInputFiles, InputFilesLoaded.size()).
+ unsigned NumUserInputFiles = 0;
+
/// \brief If non-zero, specifies the time when we last validated input
/// files. Zero means we never validated them.
///
/// The time is specified in seconds since the start of the Epoch.
- uint64_t InputFilesValidationTimestamp;
+ uint64_t InputFilesValidationTimestamp = 0;
// === Source Locations ===
@@ -222,17 +230,17 @@ public:
llvm::BitstreamCursor SLocEntryCursor;
/// \brief The number of source location entries in this AST file.
- unsigned LocalNumSLocEntries;
+ unsigned LocalNumSLocEntries = 0;
/// \brief The base ID in the source manager's view of this module.
- int SLocEntryBaseID;
+ int SLocEntryBaseID = 0;
/// \brief The base offset in the source manager's view of this module.
- unsigned SLocEntryBaseOffset;
+ unsigned SLocEntryBaseOffset = 0;
/// \brief Offsets for all of the source location entries in the
/// AST file.
- const uint32_t *SLocEntryOffsets;
+ const uint32_t *SLocEntryOffsets = nullptr;
/// \brief SLocEntries that we're going to preload.
SmallVector<uint64_t, 4> PreloadSLocEntries;
@@ -243,17 +251,17 @@ public:
// === Identifiers ===
/// \brief The number of identifiers in this AST file.
- unsigned LocalNumIdentifiers;
+ unsigned LocalNumIdentifiers = 0;
/// \brief Offsets into the identifier table data.
///
/// This array is indexed by the identifier ID (-1), and provides
/// the offset into IdentifierTableData where the string data is
/// stored.
- const uint32_t *IdentifierOffsets;
+ const uint32_t *IdentifierOffsets = nullptr;
/// \brief Base identifier ID for identifiers local to this module.
- serialization::IdentID BaseIdentifierID;
+ serialization::IdentID BaseIdentifierID = 0;
/// \brief Remapping table for identifier IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> IdentifierRemap;
@@ -262,11 +270,11 @@ public:
///
/// This pointer points into a memory buffer, where the on-disk hash
/// table for identifiers actually lives.
- const char *IdentifierTableData;
+ const char *IdentifierTableData = nullptr;
/// \brief A pointer to an on-disk hash table of opaque type
/// IdentifierHashTable.
- void *IdentifierLookupTable;
+ void *IdentifierLookupTable = nullptr;
/// \brief Offsets of identifiers that we're going to preload within
/// IdentifierTableData.
@@ -279,23 +287,23 @@ public:
llvm::BitstreamCursor MacroCursor;
/// \brief The number of macros in this AST file.
- unsigned LocalNumMacros;
+ unsigned LocalNumMacros = 0;
/// \brief Offsets of macros in the preprocessor block.
///
/// This array is indexed by the macro ID (-1), and provides
/// the offset into the preprocessor block where macro definitions are
/// stored.
- const uint32_t *MacroOffsets;
+ const uint32_t *MacroOffsets = nullptr;
/// \brief Base macro ID for macros local to this module.
- serialization::MacroID BaseMacroID;
+ serialization::MacroID BaseMacroID = 0;
/// \brief Remapping table for macro IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> MacroRemap;
/// \brief The offset of the start of the set of defined macros.
- uint64_t MacroStartOffset;
+ uint64_t MacroStartOffset = 0;
// === Detailed PreprocessingRecord ===
@@ -304,40 +312,40 @@ public:
llvm::BitstreamCursor PreprocessorDetailCursor;
/// \brief The offset of the start of the preprocessor detail cursor.
- uint64_t PreprocessorDetailStartOffset;
+ uint64_t PreprocessorDetailStartOffset = 0;
/// \brief Base preprocessed entity ID for preprocessed entities local to
/// this module.
- serialization::PreprocessedEntityID BasePreprocessedEntityID;
+ serialization::PreprocessedEntityID BasePreprocessedEntityID = 0;
/// \brief Remapping table for preprocessed entity IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> PreprocessedEntityRemap;
- const PPEntityOffset *PreprocessedEntityOffsets;
- unsigned NumPreprocessedEntities;
+ const PPEntityOffset *PreprocessedEntityOffsets = nullptr;
+ unsigned NumPreprocessedEntities = 0;
// === Header search information ===
/// \brief The number of local HeaderFileInfo structures.
- unsigned LocalNumHeaderFileInfos;
+ unsigned LocalNumHeaderFileInfos = 0;
/// \brief Actual data for the on-disk hash table of header file
/// information.
///
/// This pointer points into a memory buffer, where the on-disk hash
/// table for header file information actually lives.
- const char *HeaderFileInfoTableData;
+ const char *HeaderFileInfoTableData = nullptr;
/// \brief The on-disk hash table that contains information about each of
/// the header files.
- void *HeaderFileInfoTable;
+ void *HeaderFileInfoTable = nullptr;
// === Submodule information ===
/// \brief The number of submodules in this module.
- unsigned LocalNumSubmodules;
+ unsigned LocalNumSubmodules = 0;
/// \brief Base submodule ID for submodules local to this module.
- serialization::SubmoduleID BaseSubmoduleID;
+ serialization::SubmoduleID BaseSubmoduleID = 0;
/// \brief Remapping table for submodule IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> SubmoduleRemap;
@@ -347,14 +355,14 @@ public:
/// \brief The number of selectors new to this file.
///
/// This is the number of entries in SelectorOffsets.
- unsigned LocalNumSelectors;
+ unsigned LocalNumSelectors = 0;
/// \brief Offsets into the selector lookup table's data array
/// where each selector resides.
- const uint32_t *SelectorOffsets;
+ const uint32_t *SelectorOffsets = nullptr;
/// \brief Base selector ID for selectors local to this module.
- serialization::SelectorID BaseSelectorID;
+ serialization::SelectorID BaseSelectorID = 0;
/// \brief Remapping table for selector IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> SelectorRemap;
@@ -362,14 +370,14 @@ public:
/// \brief A pointer to the character data that comprises the selector table
///
/// The SelectorOffsets table refers into this memory.
- const unsigned char *SelectorLookupTableData;
+ const unsigned char *SelectorLookupTableData = nullptr;
/// \brief A pointer to an on-disk hash table of opaque type
/// ASTSelectorLookupTable.
///
/// This hash table provides the IDs of all selectors, and the associated
/// instance and factory methods.
- void *SelectorLookupTable;
+ void *SelectorLookupTable = nullptr;
// === Declarations ===
@@ -379,14 +387,14 @@ public:
llvm::BitstreamCursor DeclsCursor;
/// \brief The number of declarations in this AST file.
- unsigned LocalNumDecls;
+ unsigned LocalNumDecls = 0;
/// \brief Offset of each declaration within the bitstream, indexed
/// by the declaration ID (-1).
- const DeclOffset *DeclOffsets;
+ const DeclOffset *DeclOffsets = nullptr;
/// \brief Base declaration ID for declarations local to this module.
- serialization::DeclID BaseDeclID;
+ serialization::DeclID BaseDeclID = 0;
/// \brief Remapping table for declaration IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> DeclRemap;
@@ -401,15 +409,15 @@ public:
llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs;
/// \brief Array of file-level DeclIDs sorted by file.
- const serialization::DeclID *FileSortedDecls;
- unsigned NumFileSortedDecls;
+ const serialization::DeclID *FileSortedDecls = nullptr;
+ unsigned NumFileSortedDecls = 0;
/// \brief Array of category list location information within this
/// module file, sorted by the definition ID.
- const serialization::ObjCCategoriesInfo *ObjCCategoriesMap;
+ const serialization::ObjCCategoriesInfo *ObjCCategoriesMap = nullptr;
/// \brief The number of redeclaration info entries in ObjCCategoriesMap.
- unsigned LocalNumObjCCategoriesInMap;
+ unsigned LocalNumObjCCategoriesInMap = 0;
/// \brief The Objective-C category lists for categories known to this
/// module.
@@ -418,15 +426,15 @@ public:
// === Types ===
/// \brief The number of types in this AST file.
- unsigned LocalNumTypes;
+ unsigned LocalNumTypes = 0;
/// \brief Offset of each type within the bitstream, indexed by the
/// type ID, or the representation of a Type*.
- const uint32_t *TypeOffsets;
+ const uint32_t *TypeOffsets = nullptr;
/// \brief Base type ID for types local to this module as represented in
/// the global type ID space.
- serialization::TypeID BaseTypeIndex;
+ serialization::TypeID BaseTypeIndex = 0;
/// \brief Remapping table for type IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> TypeRemap;
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
index 1c4d88e979e3..fae387cac7e2 100644
--- a/include/clang/Serialization/ModuleManager.h
+++ b/include/clang/Serialization/ModuleManager.h
@@ -19,10 +19,12 @@
#include "clang/Serialization/Module.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/iterator.h"
namespace clang {
class GlobalModuleIndex;
+class MemoryBufferCache;
class ModuleMap;
class PCHContainerReader;
@@ -32,7 +34,7 @@ namespace serialization {
class ModuleManager {
/// \brief The chain of AST files, in the order in which we started to load
/// them (this order isn't really useful for anything).
- SmallVector<ModuleFile *, 2> Chain;
+ SmallVector<std::unique_ptr<ModuleFile>, 2> Chain;
/// \brief The chain of non-module PCH files. The first entry is the one named
/// by the user, the last one is the one that doesn't depend on anything
@@ -50,6 +52,9 @@ class ModuleManager {
/// FileEntry *.
FileManager &FileMgr;
+ /// Cache of PCM files.
+ IntrusiveRefCntPtr<MemoryBufferCache> PCMCache;
+
/// \brief Knows how to unwrap module containers.
const PCHContainerReader &PCHContainerRdr;
@@ -111,12 +116,18 @@ class ModuleManager {
void returnVisitState(VisitState *State);
public:
- typedef SmallVectorImpl<ModuleFile*>::iterator ModuleIterator;
- typedef SmallVectorImpl<ModuleFile*>::const_iterator ModuleConstIterator;
- typedef SmallVectorImpl<ModuleFile*>::reverse_iterator ModuleReverseIterator;
+ typedef llvm::pointee_iterator<
+ SmallVectorImpl<std::unique_ptr<ModuleFile>>::iterator>
+ ModuleIterator;
+ typedef llvm::pointee_iterator<
+ SmallVectorImpl<std::unique_ptr<ModuleFile>>::const_iterator>
+ ModuleConstIterator;
+ typedef llvm::pointee_iterator<
+ SmallVectorImpl<std::unique_ptr<ModuleFile>>::reverse_iterator>
+ ModuleReverseIterator;
typedef std::pair<uint32_t, StringRef> ModuleOffset;
- explicit ModuleManager(FileManager &FileMgr,
+ explicit ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache,
const PCHContainerReader &PCHContainerRdr);
~ModuleManager();
@@ -136,7 +147,8 @@ public:
ModuleReverseIterator rend() { return Chain.rend(); }
/// \brief A range covering the PCH and preamble module files loaded.
- llvm::iterator_range<ModuleConstIterator> pch_modules() const {
+ llvm::iterator_range<SmallVectorImpl<ModuleFile *>::const_iterator>
+ pch_modules() const {
return llvm::make_range(PCHChain.begin(), PCHChain.end());
}
@@ -152,10 +164,10 @@ public:
ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; }
/// \brief Returns the module associated with the given name
- ModuleFile *lookup(StringRef Name);
+ ModuleFile *lookup(StringRef Name) const;
/// \brief Returns the module associated with the given module file.
- ModuleFile *lookup(const FileEntry *File);
+ ModuleFile *lookup(const FileEntry *File) const;
/// \brief Returns the in-memory (virtual file) buffer with the given name
std::unique_ptr<llvm::MemoryBuffer> lookupBuffer(StringRef Name);
@@ -220,8 +232,8 @@ public:
ModuleFile *&Module,
std::string &ErrorStr);
- /// \brief Remove the given set of modules.
- void removeModules(ModuleIterator first, ModuleIterator last,
+ /// \brief Remove the modules starting from First (to the end).
+ void removeModules(ModuleIterator First,
llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
ModuleMap *modMap);
@@ -282,6 +294,8 @@ public:
/// \brief View the graphviz representation of the module graph.
void viewGraph();
+
+ MemoryBufferCache &getPCMCache() const { return *PCMCache; }
};
} } // end namespace clang::serialization
diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 69578910499f..790ba5c121c9 100644
--- a/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -45,7 +45,6 @@ def CplusplusAlpha : Package<"cplusplus">, InPackage<Alpha>, Hidden;
def CplusplusOptIn : Package<"cplusplus">, InPackage<OptIn>;
def Valist : Package<"valist">;
-def ValistAlpha : Package<"valist">, InPackage<Alpha>, Hidden;
def DeadCode : Package<"deadcode">;
def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
@@ -280,6 +279,11 @@ def VirtualCallChecker : Checker<"VirtualCall">,
let ParentPackage = CplusplusAlpha in {
+def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">,
+ HelpText<"Method calls on a moved-from object and copying a moved-from "
+ "object will be reported">,
+ DescFile<"MisusedMovedObjectChecker.cpp">;
+
def IteratorPastEndChecker : Checker<"IteratorPastEnd">,
HelpText<"Check iterators used past end">,
DescFile<"IteratorPastEndChecker.cpp">;
@@ -291,7 +295,7 @@ def IteratorPastEndChecker : Checker<"IteratorPastEnd">,
// Valist checkers.
//===----------------------------------------------------------------------===//
-let ParentPackage = ValistAlpha in {
+let ParentPackage = Valist in {
def UninitializedChecker : Checker<"Uninitialized">,
HelpText<"Check for usages of uninitialized (or already released) va_lists.">,
@@ -305,7 +309,7 @@ def CopyToSelfChecker : Checker<"CopyToSelf">,
HelpText<"Check for va_lists which are copied onto itself.">,
DescFile<"ValistChecker.cpp">;
-} // end : "alpha.valist"
+} // end : "valist"
//===----------------------------------------------------------------------===//
// Deadcode checkers.
diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def
index 3355f4b6949c..04bf41bfde4f 100644
--- a/include/clang/StaticAnalyzer/Core/Analyses.def
+++ b/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -22,6 +22,7 @@ ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateR
#endif
ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager)
+ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", CreateZ3ConstraintManager)
#ifndef ANALYSIS_DIAGNOSTICS
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index dd7a6c863be0..f9477762c758 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -321,9 +321,11 @@ class RegionChanges {
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) {
- return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
- Explicits, Regions, Call);
+ return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated,
+ Explicits, Regions,
+ LCtx, Call);
}
public:
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 0316c8fb173b..52ed260346bf 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -338,6 +338,7 @@ public:
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call);
/// \brief Run checkers when pointers escape.
@@ -443,10 +444,11 @@ public:
typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
- const InvalidatedSymbols *symbols,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call)>
+ const InvalidatedSymbols *symbols,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
+ const CallEvent *Call)>
CheckRegionChangesFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 0d1a120c9dd4..fb427f618575 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
namespace clang {
namespace ento {
@@ -29,8 +30,9 @@ class CompoundValData : public llvm::FoldingSetNode {
llvm::ImmutableList<SVal> L;
public:
- CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
- : T(t), L(l) {}
+ CompoundValData(QualType t, llvm::ImmutableList<SVal> l) : T(t), L(l) {
+ assert(NonLoc::isCompoundType(t));
+ }
typedef llvm::ImmutableList<SVal>::iterator iterator;
iterator begin() const { return L.begin(); }
@@ -47,7 +49,9 @@ class LazyCompoundValData : public llvm::FoldingSetNode {
const TypedValueRegion *region;
public:
LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r)
- : store(st), region(r) {}
+ : store(st), region(r) {
+ assert(NonLoc::isCompoundType(r->getValueType()));
+ }
const void *getStore() const { return store.getStore(); }
const TypedValueRegion *getRegion() const { return region; }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 89610ef5c17d..fa7ee62ab704 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -55,6 +55,7 @@ class CallEventManager;
class CallDescription {
friend CallEvent;
mutable IdentifierInfo *II;
+ mutable bool IsLookupDone;
StringRef FuncName;
unsigned RequiredArgs;
@@ -68,7 +69,8 @@ public:
/// call. Omit this parameter to match every occurance of call with a given
/// name regardless the number of arguments.
CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement)
- : II(nullptr), FuncName(FuncName), RequiredArgs(RequiredArgs) {}
+ : II(nullptr), IsLookupDone(false), FuncName(FuncName),
+ RequiredArgs(RequiredArgs) {}
/// \brief Get the name of the function that this object matches.
StringRef getFunctionName() const { return FuncName; }
@@ -381,7 +383,9 @@ public:
// Iterator access to formal parameters and their types.
private:
- typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun;
+ struct GetTypeFn {
+ QualType operator()(ParmVarDecl *PD) const { return PD->getType(); }
+ };
public:
/// Return call's formal parameters.
@@ -391,7 +395,7 @@ public:
/// correspond with the argument value returned by \c getArgSVal(0).
virtual ArrayRef<ParmVarDecl*> parameters() const = 0;
- typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, get_type_fun>
+ typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, GetTypeFn>
param_type_iterator;
/// Returns an iterator over the types of the call's formal parameters.
@@ -400,13 +404,11 @@ public:
/// definition because it represents a public interface, and probably has
/// more annotations.
param_type_iterator param_type_begin() const {
- return llvm::map_iterator(parameters().begin(),
- get_type_fun(&ParmVarDecl::getType));
+ return llvm::map_iterator(parameters().begin(), GetTypeFn());
}
/// \sa param_type_begin()
param_type_iterator param_type_end() const {
- return llvm::map_iterator(parameters().end(),
- get_type_fun(&ParmVarDecl::getType));
+ return llvm::map_iterator(parameters().end(), GetTypeFn());
}
// For debugging purposes only
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 6651382d9e95..c01600d5c969 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -139,6 +139,8 @@ public:
return nullptr;
}
+ /// Scan all symbols referenced by the constraints. If the symbol is not
+ /// alive, remove it.
virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper) = 0;
@@ -182,6 +184,9 @@ std::unique_ptr<ConstraintManager>
CreateRangeConstraintManager(ProgramStateManager &statemgr,
SubEngine *subengine);
+std::unique_ptr<ConstraintManager>
+CreateZ3ConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine);
+
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 591b112d60ac..067d70610868 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -237,7 +237,7 @@ public:
const CFGBlock *DstF) override;
/// Called by CoreEngine. Used to processing branching behavior
- /// at static initalizers.
+ /// at static initializers.
void processStaticInitializer(const DeclStmt *DS,
NodeBuilderContext& BuilderCtx,
ExplodedNode *Pred,
@@ -293,6 +293,7 @@ public:
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) override;
/// printState - Called by ProgramStateManager to print checker-specific data.
@@ -522,7 +523,9 @@ protected:
/// Call PointerEscape callback when a value escapes as a result of bind.
ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State,
- SVal Loc, SVal Val) override;
+ SVal Loc,
+ SVal Val,
+ const LocationContext *LCtx) override;
/// Call PointerEscape callback when a value escapes as a result of
/// region invalidation.
/// \param[in] ITraits Specifies invalidation traits for regions/symbols.
@@ -618,16 +621,16 @@ private:
void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
const CallEvent &Call);
- /// If the value of the given expression is a NonLoc, copy it into a new
- /// temporary object region, and replace the value of the expression with
- /// that.
+ /// If the value of the given expression \p InitWithAdjustments is a NonLoc,
+ /// copy it into a new temporary object region, and replace the value of the
+ /// expression with that.
///
- /// If \p ResultE is provided, the new region will be bound to this expression
- /// instead of \p E.
+ /// If \p Result is provided, the new region will be bound to this expression
+ /// instead of \p InitWithAdjustments.
ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
const LocationContext *LC,
- const Expr *E,
- const Expr *ResultE = nullptr);
+ const Expr *InitWithAdjustments,
+ const Expr *Result = nullptr);
/// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG
/// block to find the constructor expression that directly constructed into
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index da4b964424c3..29b1c4cdca04 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -182,6 +182,7 @@ protected:
MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) {
assert(classof(this));
+ assert(mgr);
}
MemRegionManager* getMemRegionManager() const override { return Mgr; }
@@ -215,9 +216,12 @@ public:
class GlobalsSpaceRegion : public MemSpaceRegion {
virtual void anchor();
+
protected:
- GlobalsSpaceRegion(MemRegionManager *mgr, Kind k)
- : MemSpaceRegion(mgr, k) {}
+ GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) : MemSpaceRegion(mgr, k) {
+ assert(classof(this));
+ }
+
public:
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
@@ -236,7 +240,9 @@ class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
const CodeTextRegion *CR;
StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr)
- : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {}
+ : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {
+ assert(cr);
+ }
public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
@@ -257,9 +263,13 @@ public:
/// RegionStoreManager::invalidateRegions (instead of finding all the dependent
/// globals, we invalidate the whole parent region).
class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
+ virtual void anchor() override;
+
protected:
NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k)
- : GlobalsSpaceRegion(mgr, k) {}
+ : GlobalsSpaceRegion(mgr, k) {
+ assert(classof(this));
+ }
public:
@@ -326,7 +336,6 @@ public:
};
class HeapSpaceRegion : public MemSpaceRegion {
- virtual void anchor();
friend class MemRegionManager;
HeapSpaceRegion(MemRegionManager *mgr)
@@ -341,10 +350,10 @@ public:
};
class UnknownSpaceRegion : public MemSpaceRegion {
- virtual void anchor();
friend class MemRegionManager;
UnknownSpaceRegion(MemRegionManager *mgr)
- : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
+ : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
+
public:
void dumpToStream(raw_ostream &os) const override;
@@ -355,13 +364,15 @@ public:
};
class StackSpaceRegion : public MemSpaceRegion {
-private:
+ virtual void anchor();
+
const StackFrameContext *SFC;
protected:
StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc)
: MemSpaceRegion(mgr, k), SFC(sfc) {
assert(classof(this));
+ assert(sfc);
}
public:
@@ -376,7 +387,6 @@ public:
};
class StackLocalsSpaceRegion : public StackSpaceRegion {
- virtual void anchor();
friend class MemRegionManager;
StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
: StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
@@ -391,7 +401,6 @@ public:
class StackArgumentsSpaceRegion : public StackSpaceRegion {
private:
- virtual void anchor();
friend class MemRegionManager;
StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
: StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
@@ -408,11 +417,15 @@ public:
/// SubRegion - A region that subsets another larger region. Most regions
/// are subclasses of SubRegion.
class SubRegion : public MemRegion {
-private:
virtual void anchor();
+
protected:
const MemRegion* superRegion;
- SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
+ SubRegion(const MemRegion *sReg, Kind k) : MemRegion(k), superRegion(sReg) {
+ assert(classof(this));
+ assert(sReg);
+ }
+
public:
const MemRegion* getSuperRegion() const {
return superRegion;
@@ -440,13 +453,18 @@ public:
/// by a call to 'alloca'.
class AllocaRegion : public SubRegion {
friend class MemRegionManager;
-protected:
+
unsigned Cnt; // Block counter. Used to distinguish different pieces of
// memory allocated by alloca at the same call site.
const Expr *Ex;
- AllocaRegion(const Expr *ex, unsigned cnt, const MemRegion *superRegion)
- : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
+ AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion)
+ : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {
+ assert(Ex);
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex,
+ unsigned Cnt, const MemRegion *superRegion);
public:
@@ -458,9 +476,6 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex,
- unsigned Cnt, const MemRegion *superRegion);
-
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion* R) {
@@ -470,10 +485,12 @@ public:
/// TypedRegion - An abstract class representing regions that are typed.
class TypedRegion : public SubRegion {
-public:
- void anchor() override;
+ virtual void anchor() override;
+
protected:
- TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
+ TypedRegion(const MemRegion *sReg, Kind k) : SubRegion(sReg, k) {
+ assert(classof(this));
+ }
public:
virtual QualType getLocationType() const = 0;
@@ -492,10 +509,12 @@ public:
/// TypedValueRegion - An abstract class representing regions having a typed value.
class TypedValueRegion : public TypedRegion {
-public:
- void anchor() override;
+ virtual void anchor() override;
+
protected:
- TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {}
+ TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {
+ assert(classof(this));
+ }
public:
virtual QualType getValueType() const = 0;
@@ -524,10 +543,13 @@ public:
class CodeTextRegion : public TypedRegion {
-public:
- void anchor() override;
+ virtual void anchor() override;
+
protected:
- CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {}
+ CodeTextRegion(const MemSpaceRegion *sreg, Kind k) : TypedRegion(sreg, k) {
+ assert(classof(this));
+ }
+
public:
bool isBoundable() const override { return false; }
@@ -539,13 +561,19 @@ public:
/// FunctionCodeRegion - A region that represents code texts of function.
class FunctionCodeRegion : public CodeTextRegion {
+ friend class MemRegionManager;
+
const NamedDecl *FD;
-public:
- FunctionCodeRegion(const NamedDecl *fd, const MemRegion* sreg)
+
+ FunctionCodeRegion(const NamedDecl *fd, const CodeSpaceRegion* sreg)
: CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) {
assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
}
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD,
+ const MemRegion*);
+
+public:
QualType getLocationType() const override {
const ASTContext &Ctx = getContext();
if (const FunctionDecl *D = dyn_cast<FunctionDecl>(FD)) {
@@ -568,9 +596,6 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD,
- const MemRegion*);
-
static bool classof(const MemRegion* R) {
return R->getKind() == FunctionCodeRegionKind;
}
@@ -591,8 +616,16 @@ class BlockCodeRegion : public CodeTextRegion {
CanQualType locTy;
BlockCodeRegion(const BlockDecl *bd, CanQualType lTy,
- AnalysisDeclContext *ac, const MemRegion* sreg)
- : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {}
+ AnalysisDeclContext *ac, const CodeSpaceRegion* sreg)
+ : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {
+ assert(bd);
+ assert(ac);
+ assert(lTy->getTypePtr()->isBlockPointerType());
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
+ CanQualType, const AnalysisDeclContext*,
+ const MemRegion*);
public:
QualType getLocationType() const override {
@@ -609,10 +642,6 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
- CanQualType, const AnalysisDeclContext*,
- const MemRegion*);
-
static bool classof(const MemRegion* R) {
return R->getKind() == BlockCodeRegionKind;
}
@@ -626,6 +655,7 @@ public:
/// variables.
class BlockDataRegion : public TypedRegion {
friend class MemRegionManager;
+
const BlockCodeRegion *BC;
const LocationContext *LC; // Can be null */
unsigned BlockCount;
@@ -633,10 +663,19 @@ class BlockDataRegion : public TypedRegion {
void *OriginalVars;
BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc,
- unsigned count, const MemRegion *sreg)
- : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
- BlockCount(count),
- ReferencedVars(nullptr), OriginalVars(nullptr) {}
+ unsigned count, const MemSpaceRegion *sreg)
+ : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
+ BlockCount(count), ReferencedVars(nullptr), OriginalVars(nullptr) {
+ assert(bc);
+ assert(lc);
+ assert(isa<GlobalImmutableSpaceRegion>(sreg) ||
+ isa<StackLocalsSpaceRegion>(sreg) ||
+ isa<UnknownSpaceRegion>(sreg));
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
+ const LocationContext *, unsigned,
+ const MemRegion *);
public:
const BlockCodeRegion *getCodeRegion() const { return BC; }
@@ -686,10 +725,6 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
- const LocationContext *, unsigned,
- const MemRegion *);
-
static bool classof(const MemRegion* R) {
return R->getKind() == BlockDataRegionKind;
}
@@ -705,13 +740,20 @@ private:
/// map the concept of symbolic values into the domain of regions. Symbolic
/// regions do not need to be typed.
class SymbolicRegion : public SubRegion {
-protected:
+ friend class MemRegionManager;
+
const SymbolRef sym;
-public:
- SymbolicRegion(const SymbolRef s, const MemRegion* sreg)
- : SubRegion(sreg, SymbolicRegionKind), sym(s) {}
+ SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg)
+ : SubRegion(sreg, SymbolicRegionKind), sym(s) {
+ assert(s);
+ assert(s->getType()->isAnyPointerType() ||
+ s->getType()->isReferenceType() ||
+ s->getType()->isBlockPointerType());
+ assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg));
+ }
+public:
SymbolRef getSymbol() const {
return sym;
}
@@ -736,11 +778,13 @@ public:
/// StringRegion - Region associated with a StringLiteral.
class StringRegion : public TypedValueRegion {
friend class MemRegionManager;
+
const StringLiteral* Str;
-protected:
- StringRegion(const StringLiteral* str, const MemRegion* sreg)
- : TypedValueRegion(sreg, StringRegionKind), Str(str) {}
+ StringRegion(const StringLiteral *str, const GlobalInternalSpaceRegion *sreg)
+ : TypedValueRegion(sreg, StringRegionKind), Str(str) {
+ assert(str);
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const StringLiteral* Str,
@@ -772,12 +816,15 @@ public:
/// The region associated with an ObjCStringLiteral.
class ObjCStringRegion : public TypedValueRegion {
friend class MemRegionManager;
+
const ObjCStringLiteral* Str;
-protected:
-
- ObjCStringRegion(const ObjCStringLiteral* str, const MemRegion* sreg)
- : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {}
-
+
+ ObjCStringRegion(const ObjCStringLiteral *str,
+ const GlobalInternalSpaceRegion *sreg)
+ : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {
+ assert(str);
+ }
+
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const ObjCStringLiteral* Str,
const MemRegion* superRegion);
@@ -807,12 +854,17 @@ public:
/// Compound literals are essentially temporaries that are stack allocated
/// or in the global constant pool.
class CompoundLiteralRegion : public TypedValueRegion {
-private:
friend class MemRegionManager;
+
const CompoundLiteralExpr *CL;
- CompoundLiteralRegion(const CompoundLiteralExpr *cl, const MemRegion* sReg)
- : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
+ CompoundLiteralRegion(const CompoundLiteralExpr *cl,
+ const MemSpaceRegion *sReg)
+ : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {
+ assert(cl);
+ assert(isa<GlobalInternalSpaceRegion>(sReg) ||
+ isa<StackLocalsSpaceRegion>(sReg));
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const CompoundLiteralExpr *CL,
@@ -839,8 +891,11 @@ class DeclRegion : public TypedValueRegion {
protected:
const Decl *D;
- DeclRegion(const Decl *d, const MemRegion* sReg, Kind k)
- : TypedValueRegion(sReg, k), D(d) {}
+ DeclRegion(const Decl *d, const MemRegion *sReg, Kind k)
+ : TypedValueRegion(sReg, k), D(d) {
+ assert(classof(this));
+ assert(d);
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
const MemRegion* superRegion, Kind k);
@@ -859,17 +914,24 @@ class VarRegion : public DeclRegion {
friend class MemRegionManager;
// Constructors and private methods.
- VarRegion(const VarDecl *vd, const MemRegion* sReg)
- : DeclRegion(vd, sReg, VarRegionKind) {}
+ VarRegion(const VarDecl *vd, const MemRegion *sReg)
+ : DeclRegion(vd, sReg, VarRegionKind) {
+ // VarRegion appears in unknown space when it's a block variable as seen
+ // from a block using it, when this block is analyzed at top-level.
+ // Other block variables appear within block data regions,
+ // which, unlike everything else on this list, are not memory spaces.
+ assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) ||
+ isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
const MemRegion *superRegion) {
DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
}
+public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
-public:
const VarDecl *getDecl() const { return cast<VarDecl>(D); }
const StackFrameContext *getStackFrame() const;
@@ -895,17 +957,19 @@ public:
/// referred to by 'this', but rather 'this' itself.
class CXXThisRegion : public TypedValueRegion {
friend class MemRegionManager;
+
CXXThisRegion(const PointerType *thisPointerTy,
- const MemRegion *sReg)
- : TypedValueRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
+ const StackArgumentsSpaceRegion *sReg)
+ : TypedValueRegion(sReg, CXXThisRegionKind),
+ ThisPointerTy(thisPointerTy) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
const PointerType *PT,
const MemRegion *sReg);
+public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
-public:
QualType getValueType() const override {
return QualType(ThisPointerTy, 0);
}
@@ -923,9 +987,14 @@ private:
class FieldRegion : public DeclRegion {
friend class MemRegionManager;
- FieldRegion(const FieldDecl *fd, const MemRegion* sReg)
+ FieldRegion(const FieldDecl *fd, const SubRegion* sReg)
: DeclRegion(fd, sReg, FieldRegionKind) {}
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
+ }
+
public:
const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
@@ -936,11 +1005,6 @@ public:
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
- const MemRegion* superRegion) {
- DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
- }
-
static bool classof(const MemRegion* R) {
return R->getKind() == FieldRegionKind;
}
@@ -954,10 +1018,9 @@ public:
};
class ObjCIvarRegion : public DeclRegion {
-
friend class MemRegionManager;
- ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg);
+ ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg);
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
const MemRegion* superRegion);
@@ -982,7 +1045,6 @@ public:
class ElementRegion;
class RegionRawOffset {
-private:
friend class ElementRegion;
const MemRegion *Region;
@@ -1007,9 +1069,9 @@ class ElementRegion : public TypedValueRegion {
QualType ElementType;
NonLoc Index;
- ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg)
- : TypedValueRegion(sReg, ElementRegionKind),
- ElementType(elementType), Index(Idx) {
+ ElementRegion(QualType elementType, NonLoc Idx, const SubRegion *sReg)
+ : TypedValueRegion(sReg, ElementRegionKind),
+ ElementType(elementType), Index(Idx) {
assert((!Idx.getAs<nonloc::ConcreteInt>() ||
Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) &&
"The index must be signed");
@@ -1047,12 +1109,16 @@ class CXXTempObjectRegion : public TypedValueRegion {
Expr const *Ex;
- CXXTempObjectRegion(Expr const *E, MemRegion const *sReg)
- : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {}
+ CXXTempObjectRegion(Expr const *E, MemSpaceRegion const *sReg)
+ : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {
+ assert(E);
+ assert(isa<StackLocalsSpaceRegion>(sReg) ||
+ isa<GlobalInternalSpaceRegion>(sReg));
+ }
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
Expr const *E, const MemRegion *sReg);
-
+
public:
const Expr *getExpr() const { return Ex; }
@@ -1077,8 +1143,10 @@ class CXXBaseObjectRegion : public TypedValueRegion {
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data;
CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual,
- const MemRegion *SReg)
- : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {}
+ const SubRegion *SReg)
+ : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {
+ assert(RD);
+ }
static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD,
bool IsVirtual, const MemRegion *SReg);
@@ -1204,16 +1272,16 @@ public:
/// getVarRegion - Retrieve or create the memory region associated with
/// a specified VarDecl and super region.
- const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR);
-
+ const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR);
+
/// getElementRegion - Retrieve the memory region associated with the
/// associated element type, index, and super region.
const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx,
- const MemRegion *superRegion,
+ const SubRegion *superRegion,
ASTContext &Ctx);
const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER,
- const MemRegion *superRegion) {
+ const SubRegion *superRegion) {
return getElementRegion(ER->getElementType(), ER->getIndex(),
superRegion, ER->getContext());
}
@@ -1223,10 +1291,10 @@ public:
/// memory region (which typically represents the memory representing
/// a structure or class).
const FieldRegion *getFieldRegion(const FieldDecl *fd,
- const MemRegion* superRegion);
+ const SubRegion* superRegion);
const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
- const MemRegion *superRegion) {
+ const SubRegion *superRegion) {
return getFieldRegion(FR->getDecl(), superRegion);
}
@@ -1235,7 +1303,7 @@ public:
/// to the containing region (which typically represents the Objective-C
/// object).
const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd,
- const MemRegion* superRegion);
+ const SubRegion* superRegion);
const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
LocationContext const *LC);
@@ -1245,14 +1313,14 @@ public:
///
/// The type of \p Super is assumed be a class deriving from \p BaseClass.
const CXXBaseObjectRegion *
- getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super,
+ getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const SubRegion *Super,
bool IsVirtual);
/// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different
/// super region.
const CXXBaseObjectRegion *
getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg,
- const MemRegion *superRegion) {
+ const SubRegion *superRegion) {
return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion,
baseReg->isVirtual());
}
@@ -1276,17 +1344,22 @@ public:
const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex);
private:
- template <typename RegionTy, typename A1>
- RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion);
-
- template <typename RegionTy, typename A1, typename A2>
- RegionTy* getSubRegion(const A1 a1, const A2 a2,
- const MemRegion* superRegion);
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1,
+ const SuperTy* superRegion);
+
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty, typename Arg2Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const SuperTy* superRegion);
+
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const Arg3Ty arg3,
+ const SuperTy* superRegion);
- template <typename RegionTy, typename A1, typename A2, typename A3>
- RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3,
- const MemRegion* superRegion);
-
template <typename REG>
const REG* LazyAllocate(REG*& region);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 463b375fda30..2910ef4212cc 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -229,11 +229,12 @@ public:
ProgramStateRef bindLoc(Loc location,
SVal V,
+ const LocationContext *LCtx,
bool notifyChanges = true) const;
- ProgramStateRef bindLoc(SVal location, SVal V) const;
+ ProgramStateRef bindLoc(SVal location, SVal V, const LocationContext *LCtx) const;
- ProgramStateRef bindDefault(SVal loc, SVal V) const;
+ ProgramStateRef bindDefault(SVal loc, SVal V, const LocationContext *LCtx) const;
ProgramStateRef killBinding(Loc LV) const;
@@ -681,9 +682,9 @@ ProgramState::assumeInclusiveRange(DefinedOrUnknownSVal Val,
this, Val.castAs<NonLoc>(), From, To);
}
-inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const {
+inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V, const LocationContext *LCtx) const {
if (Optional<Loc> L = LV.getAs<Loc>())
- return bindLoc(*L, V);
+ return bindLoc(*L, V, LCtx);
return this;
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index a4c01fc45334..14aa3af37620 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -112,6 +112,11 @@ public:
/// Evaluates a given SVal. If the SVal has only one possible (integer) value,
/// that value is returned. Otherwise, returns NULL.
virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0;
+
+ /// Simplify symbolic expressions within a given SVal. Return an SVal
+ /// that represents the same value, but is hopefully easier to work with
+ /// than the original SVal.
+ virtual SVal simplifySVal(ProgramStateRef State, SVal Val) = 0;
/// Constructs a symbolic expression for two non-location values.
SVal makeSymExprValNN(ProgramStateRef state, BinaryOperator::Opcode op,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index cc3c02a02c64..935f0018324a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -41,6 +41,22 @@ class MemRegionManager;
class ProgramStateManager;
class SValBuilder;
+namespace nonloc {
+/// Sub-kinds for NonLoc values.
+enum Kind {
+#define NONLOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
+}
+
+namespace loc {
+/// Sub-kinds for Loc values.
+enum Kind {
+#define LOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
+}
+
/// SVal - This represents a symbolic expression, which can be either
/// an L-value or an R-value.
///
@@ -75,10 +91,7 @@ public:
template<typename T>
T castAs() const {
assert(T::isKind(*this));
- T t;
- SVal& sv = t;
- sv = *this;
- return t;
+ return *static_cast<const T *>(this);
}
/// \brief Convert to the specified SVal type, returning None if this SVal is
@@ -87,10 +100,7 @@ public:
Optional<T> getAs() const {
if (!T::isKind(*this))
return None;
- T t;
- SVal& sv = t;
- sv = *this;
- return t;
+ return *static_cast<const T *>(this);
}
/// BufferTy - A temporary buffer to hold a set of SVals.
@@ -273,6 +283,11 @@ protected:
public:
void dumpToStream(raw_ostream &Out) const;
+ static inline bool isCompoundType(QualType T) {
+ return T->isArrayType() || T->isRecordType() ||
+ T->isComplexType() || T->isVectorType();
+ }
+
private:
friend class SVal;
static bool isKind(const SVal& V) {
@@ -307,15 +322,11 @@ private:
namespace nonloc {
-enum Kind {
-#define NONLOC_SVAL(Id, Parent) Id ## Kind,
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-};
-
/// \brief Represents symbolic expression.
class SymbolVal : public NonLoc {
public:
- SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
+ SymbolVal() = delete;
+ SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) { assert(sym); }
SymbolRef getSymbol() const {
return (const SymExpr*) Data;
@@ -327,7 +338,6 @@ public:
private:
friend class SVal;
- SymbolVal() {}
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind &&
V.getSubKind() == SymbolValKind;
@@ -373,7 +383,11 @@ class LocAsInteger : public NonLoc {
explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
: NonLoc(LocAsIntegerKind, &data) {
- assert (data.first.getAs<Loc>());
+ // We do not need to represent loc::ConcreteInt as LocAsInteger,
+ // as it'd collapse into a nonloc::ConcreteInt instead.
+ assert(data.first.getBaseKind() == LocKind &&
+ (data.first.getSubKind() == loc::MemRegionValKind ||
+ data.first.getSubKind() == loc::GotoLabelKind));
}
public:
@@ -513,14 +527,11 @@ private:
namespace loc {
-enum Kind {
-#define LOC_SVAL(Id, Parent) Id ## Kind,
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-};
-
class GotoLabel : public Loc {
public:
- explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {}
+ explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) {
+ assert(Label);
+ }
const LabelDecl *getLabel() const {
return static_cast<const LabelDecl*>(Data);
@@ -541,7 +552,9 @@ private:
class MemRegionVal : public Loc {
public:
- explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {}
+ explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {
+ assert(r);
+ }
/// \brief Get the underlining region.
const MemRegion* getRegion() const {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
new file mode 100644
index 000000000000..2c9802bbc536
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
@@ -0,0 +1,92 @@
+//== SimpleConstraintManager.h ----------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simplified constraint manager backend.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SIMPLECONSTRAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SIMPLECONSTRAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+namespace clang {
+
+namespace ento {
+
+class SimpleConstraintManager : public ConstraintManager {
+ SubEngine *SU;
+ SValBuilder &SVB;
+
+public:
+ SimpleConstraintManager(SubEngine *subengine, SValBuilder &SB)
+ : SU(subengine), SVB(SB) {}
+
+ ~SimpleConstraintManager() override;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from ConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ /// Ensures that the DefinedSVal conditional is expressed as a NonLoc by
+ /// creating boolean casts to handle Loc's.
+ ProgramStateRef assume(ProgramStateRef State, DefinedSVal Cond,
+ bool Assumption) override;
+
+ ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override;
+
+protected:
+ //===------------------------------------------------------------------===//
+ // Interface that subclasses must implement.
+ //===------------------------------------------------------------------===//
+
+ /// Given a symbolic expression that can be reasoned about, assume that it is
+ /// true/false and generate the new program state.
+ virtual ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) = 0;
+
+ /// Given a symbolic expression within the range [From, To], assume that it is
+ /// true/false and generate the new program state.
+ /// This function is used to handle case ranges produced by a language
+ /// extension for switch case statements.
+ virtual ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State,
+ SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) = 0;
+
+ /// Given a symbolic expression that cannot be reasoned about, assume that
+ /// it is zero/nonzero and add it directly to the solver state.
+ virtual ProgramStateRef assumeSymUnsupported(ProgramStateRef State,
+ SymbolRef Sym,
+ bool Assumption) = 0;
+
+ //===------------------------------------------------------------------===//
+ // Internal implementation.
+ //===------------------------------------------------------------------===//
+
+ BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); }
+ SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); }
+
+private:
+ ProgramStateRef assume(ProgramStateRef State, NonLoc Cond, bool Assumption);
+
+ ProgramStateRef assumeAux(ProgramStateRef State, NonLoc Cond,
+ bool Assumption);
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index fa7d3f72abf1..7619f22f4013 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -59,6 +59,30 @@ public:
/// \return The value bound to the location \c loc.
virtual SVal getBinding(Store store, Loc loc, QualType T = QualType()) = 0;
+ /// Return the default value bound to a region in a given store. The default
+ /// binding is the value of sub-regions that were not initialized separately
+ /// from their base region. For example, if the structure is zero-initialized
+ /// upon construction, this method retrieves the concrete zero value, even if
+ /// some or all fields were later overwritten manually. Default binding may be
+ /// an unknown, undefined, concrete, or symbolic value.
+ /// \param[in] store The store in which to make the lookup.
+ /// \param[in] R The region to find the default binding for.
+ /// \return The default value bound to the region in the store, if a default
+ /// binding exists.
+ virtual Optional<SVal> getDefaultBinding(Store store, const MemRegion *R) = 0;
+
+ /// Return the default value bound to a LazyCompoundVal. The default binding
+ /// is used to represent the value of any fields or elements within the
+ /// structure represented by the LazyCompoundVal which were not initialized
+ /// explicitly separately from the whole structure. Default binding may be an
+ /// unknown, undefined, concrete, or symbolic value.
+ /// \param[in] lcv The lazy compound value.
+ /// \return The default value bound to the LazyCompoundVal \c lcv, if a
+ /// default binding exists.
+ Optional<SVal> getDefaultBinding(nonloc::LazyCompoundVal lcv) {
+ return getDefaultBinding(lcv.getStore(), lcv.getRegion());
+ }
+
/// Return a state with the specified value bound to the given location.
/// \param[in] store The analysis state.
/// \param[in] loc The symbolic memory location.
@@ -136,7 +160,7 @@ public:
/// valid only if Failed flag is set to false.
SVal attemptDownCast(SVal Base, QualType DerivedPtrType, bool &Failed);
- const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
+ const ElementRegion *GetElementZeroRegion(const SubRegion *R, QualType T);
/// castRegion - Used by ExprEngine::VisitCast to handle casts from
/// a MemRegion* to a specific location type. 'R' is the region being
@@ -235,8 +259,9 @@ public:
virtual void iterBindings(Store store, BindingsHandler& f) = 0;
protected:
- const MemRegion *MakeElementRegion(const MemRegion *baseRegion,
- QualType pointeeTy, uint64_t index = 0);
+ const ElementRegion *MakeElementRegion(const SubRegion *baseRegion,
+ QualType pointeeTy,
+ uint64_t index = 0);
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 581ef206cff3..8ccd34751bbe 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -83,7 +83,7 @@ public:
const CFGBlock *DstF) = 0;
/// Called by CoreEngine. Used to processing branching behavior
- /// at static initalizers.
+ /// at static initializers.
virtual void processStaticInitializer(const DeclStmt *DS,
NodeBuilderContext& BuilderCtx,
ExplodedNode *Pred,
@@ -131,17 +131,19 @@ public:
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) = 0;
inline ProgramStateRef
processRegionChange(ProgramStateRef state,
- const MemRegion* MR) {
- return processRegionChanges(state, nullptr, MR, MR, nullptr);
+ const MemRegion* MR,
+ const LocationContext *LCtx) {
+ return processRegionChanges(state, nullptr, MR, MR, LCtx, nullptr);
}
virtual ProgramStateRef
- processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val) = 0;
+ processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val, const LocationContext *LCtx) = 0;
virtual ProgramStateRef
notifyCheckersOfPointerEscape(ProgramStateRef State,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
index 18bc60754b81..f72033955ec3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
@@ -42,6 +42,12 @@ private:
protected:
SymExpr(Kind k) : K(k) {}
+ static bool isValidTypeForSymbol(QualType T) {
+ // FIXME: Depending on whether we choose to deprecate structural symbols,
+ // this may become much stricter.
+ return !T.isNull() && !T->isVoidType();
+ }
+
public:
virtual ~SymExpr() {}
@@ -103,7 +109,9 @@ class SymbolData : public SymExpr {
const SymbolID Sym;
protected:
- SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
+ SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {
+ assert(classof(this));
+ }
public:
~SymbolData() override {}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index f00dce568e3a..e9701142cd9e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -44,7 +44,10 @@ class SymbolRegionValue : public SymbolData {
public:
SymbolRegionValue(SymbolID sym, const TypedValueRegion *r)
- : SymbolData(SymbolRegionValueKind, sym), R(r) {}
+ : SymbolData(SymbolRegionValueKind, sym), R(r) {
+ assert(r);
+ assert(isValidTypeForSymbol(r->getValueType()));
+ }
const TypedValueRegion* getRegion() const { return R; }
@@ -81,7 +84,15 @@ public:
SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx,
QualType t, unsigned count, const void *symbolTag)
: SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count),
- LCtx(lctx), SymbolTag(symbolTag) {}
+ LCtx(lctx), SymbolTag(symbolTag) {
+ // FIXME: 's' might be a nullptr if we're conducting invalidation
+ // that was caused by a destructor call on a temporary object,
+ // which has no statement associated with it.
+ // Due to this, we might be creating the same invalidation symbol for
+ // two different invalidation passes (for two different temporaries).
+ assert(lctx);
+ assert(isValidTypeForSymbol(t));
+ }
const Stmt *getStmt() const { return S; }
unsigned getCount() const { return Count; }
@@ -120,7 +131,11 @@ class SymbolDerived : public SymbolData {
public:
SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r)
- : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {}
+ : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {
+ assert(parent);
+ assert(r);
+ assert(isValidTypeForSymbol(r->getValueType()));
+ }
SymbolRef getParentSymbol() const { return parentSymbol; }
const TypedValueRegion *getRegion() const { return R; }
@@ -155,7 +170,9 @@ class SymbolExtent : public SymbolData {
public:
SymbolExtent(SymbolID sym, const SubRegion *r)
- : SymbolData(SymbolExtentKind, sym), R(r) {}
+ : SymbolData(SymbolExtentKind, sym), R(r) {
+ assert(r);
+ }
const SubRegion *getRegion() const { return R; }
@@ -193,7 +210,13 @@ public:
SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
const LocationContext *LCtx, unsigned count, const void *tag)
: SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx),
- Count(count), Tag(tag) {}
+ Count(count), Tag(tag) {
+ assert(r);
+ assert(s);
+ assert(isValidTypeForSymbol(t));
+ assert(LCtx);
+ assert(tag);
+ }
const MemRegion *getRegion() const { return R; }
const Stmt *getStmt() const { return S; }
@@ -236,8 +259,13 @@ class SymbolCast : public SymExpr {
QualType ToTy;
public:
- SymbolCast(const SymExpr *In, QualType From, QualType To) :
- SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) { }
+ SymbolCast(const SymExpr *In, QualType From, QualType To)
+ : SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) {
+ assert(In);
+ assert(isValidTypeForSymbol(From));
+ // FIXME: GenericTaintChecker creates symbols of void type.
+ // Otherwise, 'To' should also be a valid type.
+ }
QualType getType() const override { return ToTy; }
@@ -270,7 +298,10 @@ class BinarySymExpr : public SymExpr {
protected:
BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t)
- : SymExpr(k), Op(op), T(t) {}
+ : SymExpr(k), Op(op), T(t) {
+ assert(classof(this));
+ assert(isValidTypeForSymbol(t));
+ }
public:
// FIXME: We probably need to make this out-of-line to avoid redundant
@@ -293,8 +324,10 @@ class SymIntExpr : public BinarySymExpr {
public:
SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
- const llvm::APSInt& rhs, QualType t)
- : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {}
+ const llvm::APSInt &rhs, QualType t)
+ : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(lhs);
+ }
void dumpToStream(raw_ostream &os) const override;
@@ -327,9 +360,11 @@ class IntSymExpr : public BinarySymExpr {
const SymExpr *RHS;
public:
- IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op,
+ IntSymExpr(const llvm::APSInt &lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType t)
- : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(rhs);
+ }
void dumpToStream(raw_ostream &os) const override;
@@ -364,7 +399,10 @@ class SymSymExpr : public BinarySymExpr {
public:
SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
QualType t)
- : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(lhs);
+ assert(rhs);
+ }
const SymExpr *getLHS() const { return LHS; }
const SymExpr *getRHS() const { return RHS; }
diff --git a/include/clang/Tooling/Refactoring/AtomicChange.h b/include/clang/Tooling/Refactoring/AtomicChange.h
new file mode 100644
index 000000000000..9cccd78677b1
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/AtomicChange.h
@@ -0,0 +1,135 @@
+//===--- AtomicChange.h - AtomicChange class --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines AtomicChange which is used to create a set of source
+// changes, e.g. replacements and header insertions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
+#define LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace tooling {
+
+/// \brief An atomic change is used to create and group a set of source edits,
+/// e.g. replacements or header insertions. Edits in an AtomicChange should be
+/// related, e.g. replacements for the same type reference and the corresponding
+/// header insertion/deletion.
+///
+/// An AtomicChange is uniquely identified by a key and will either be fully
+/// applied or not applied at all.
+///
+/// Calling setError on an AtomicChange stores the error message and marks it as
+/// bad, i.e. none of its source edits will be applied.
+class AtomicChange {
+public:
+ /// \brief Creates an atomic change around \p KeyPosition with the key being a
+ /// concatenation of the file name and the offset of \p KeyPosition.
+ /// \p KeyPosition should be the location of the key syntactical element that
+ /// is being changed, e.g. the call to a refactored method.
+ AtomicChange(const SourceManager &SM, SourceLocation KeyPosition);
+
+ /// \brief Creates an atomic change for \p FilePath with a customized key.
+ AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key)
+ : Key(Key), FilePath(FilePath) {}
+
+ /// \brief Returns the atomic change as a YAML string.
+ std::string toYAMLString();
+
+ /// \brief Converts a YAML-encoded automic change to AtomicChange.
+ static AtomicChange convertFromYAML(llvm::StringRef YAMLContent);
+
+ /// \brief Returns the key of this change, which is a concatenation of the
+ /// file name and offset of the key position.
+ const std::string &getKey() const { return Key; }
+
+ /// \brief Returns the path of the file containing this atomic change.
+ const std::string &getFilePath() const { return FilePath; }
+
+ /// \brief If this change could not be created successfully, e.g. because of
+ /// conflicts among replacements, use this to set an error description.
+ /// Thereby, places that cannot be fixed automatically can be gathered when
+ /// applying changes.
+ void setError(llvm::StringRef Error) { this->Error = Error; }
+
+ /// \brief Returns whether an error has been set on this list.
+ bool hasError() const { return !Error.empty(); }
+
+ /// \brief Returns the error message or an empty string if it does not exist.
+ const std::string &getError() const { return Error; }
+
+ /// \brief Adds a replacement that replaces the given Range with
+ /// ReplacementText.
+ /// \returns An llvm::Error carrying ReplacementError on error.
+ llvm::Error replace(const SourceManager &SM, const CharSourceRange &Range,
+ llvm::StringRef ReplacementText);
+
+ /// \brief Adds a replacement that replaces range [Loc, Loc+Length) with
+ /// \p Text.
+ /// \returns An llvm::Error carrying ReplacementError on error.
+ llvm::Error replace(const SourceManager &SM, SourceLocation Loc,
+ unsigned Length, llvm::StringRef Text);
+
+ /// \brief Adds a replacement that inserts \p Text at \p Loc. If this
+ /// insertion conflicts with an existing insertion (at the same position),
+ /// this will be inserted before/after the existing insertion depending on
+ /// \p InsertAfter. Users should use `replace` with `Length=0` instead if they
+ /// do not want conflict resolving by default. If the conflicting replacement
+ /// is not an insertion, an error is returned.
+ ///
+ /// \returns An llvm::Error carrying ReplacementError on error.
+ llvm::Error insert(const SourceManager &SM, SourceLocation Loc,
+ llvm::StringRef Text, bool InsertAfter = true);
+
+ /// \brief Adds a header into the file that contains the key position.
+ /// Header can be in angle brackets or double quotation marks. By default
+ /// (header is not quoted), header will be surrounded with double quotes.
+ void addHeader(llvm::StringRef Header);
+
+ /// \brief Removes a header from the file that contains the key position.
+ void removeHeader(llvm::StringRef Header);
+
+ /// \brief Returns a const reference to existing replacements.
+ const Replacements &getReplacements() const { return Replaces; }
+
+ llvm::ArrayRef<std::string> getInsertedHeaders() const {
+ return InsertedHeaders;
+ }
+
+ llvm::ArrayRef<std::string> getRemovedHeaders() const {
+ return RemovedHeaders;
+ }
+
+private:
+ AtomicChange() {}
+
+ AtomicChange(std::string Key, std::string FilePath, std::string Error,
+ std::vector<std::string> InsertedHeaders,
+ std::vector<std::string> RemovedHeaders,
+ clang::tooling::Replacements Replaces);
+
+ // This uniquely identifies an AtomicChange.
+ std::string Key;
+ std::string FilePath;
+ std::string Error;
+ std::vector<std::string> InsertedHeaders;
+ std::vector<std::string> RemovedHeaders;
+ tooling::Replacements Replaces;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index b531a66dbab3..7b337b061a03 100644
--- a/lib/AST/ASTContext.cpp
+++ b/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),
@@ -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());
@@ -2691,8 +2695,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 +2768,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");
@@ -3785,12 +3789,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 +3874,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 +4442,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 {
@@ -5922,7 +5947,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:
@@ -6337,6 +6361,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:
@@ -8043,20 +8068,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 +8153,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 +8193,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();
@@ -8696,7 +8728,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::Count);
Str = End;
}
if (c == '*')
@@ -8788,7 +8821,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 +8893,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 +8917,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;
- // 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;
+ // Otherwise, let the static local variable inherit its linkage from the
+ // nearest enclosing function.
+ auto StaticLocalLinkage =
+ Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
+
+ // 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 +9057,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);
@@ -9488,6 +9545,18 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
return getTargetInfo().getNullPointerValue(AS);
}
+unsigned ASTContext::getTargetAddressSpace(unsigned AS) const {
+ // For OpenCL, only function local variables are not explicitly marked with
+ // an address space in the AST, and these need to be the address space of
+ // alloca.
+ if (!AS && LangOpts.OpenCL)
+ return getTargetInfo().getDataLayout().getAllocaAddrSpace();
+ if (AS >= LangAS::Count)
+ return AS - LangAS::Count;
+ 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/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 62261ccc905b..ef491ab06f8c 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/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 ";
@@ -1463,6 +1469,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 +1479,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 +1489,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 +2513,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 +2531,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/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 1ccb746633a7..95492825eb9d 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -72,7 +72,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 +278,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) {
@@ -397,6 +399,9 @@ 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);
/// \brief Determine structural equivalence of two expressions.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
@@ -421,8 +426,103 @@ static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
NestedNameSpecifier *NNS1,
NestedNameSpecifier *NNS2) {
- // FIXME: Implement!
- return true;
+ 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;
}
/// \brief Determine whether two template arguments are equivalent.
@@ -783,6 +883,20 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
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,
@@ -1976,6 +2090,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 +2264,7 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From,
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
return;
case DeclarationName::CXXOperatorName: {
@@ -2231,8 +2363,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
@@ -2785,7 +2919,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;
@@ -2874,7 +3008,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
if (!DC->isFunctionOrMethod()) {
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;
@@ -3671,6 +3805,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
if (ImportDefinition(D, ToVar))
return nullptr;
+ if (D->isConstexpr())
+ ToVar->setConstexpr(true);
+
return ToVar;
}
@@ -3724,8 +3861,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();
@@ -4424,8 +4580,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 +4911,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 +4958,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 +5220,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 +6074,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 +6224,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 +6847,27 @@ 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);
+}
+
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTContext &FromContext, FileManager &FromFileManager,
bool MinimalImport)
@@ -6839,14 +7074,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 +7091,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 +7113,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 +7476,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())
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index e28bd2e16d17..13bf352c2f21 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -31,6 +31,7 @@ add_clang_library(clangAST
ExprConstant.cpp
ExprCXX.cpp
ExprObjC.cpp
+ ExternalASTMerger.cpp
ExternalASTSource.cpp
InheritViz.cpp
ItaniumCXXABI.cpp
@@ -40,6 +41,7 @@ add_clang_library(clangAST
MicrosoftMangle.cpp
NestedNameSpecifier.cpp
NSAPI.cpp
+ ODRHash.cpp
OpenMPClause.cpp
ParentMap.cpp
RawCommentList.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index a97d6a22e7b3..56fb0464078f 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -88,7 +88,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 +109,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);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 81f08787d515..2b22e5bb50a5 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1414,6 +1414,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 +2148,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 +2179,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;
@@ -2510,7 +2508,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;
}
@@ -3744,6 +3742,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();
@@ -4230,6 +4242,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/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 6111abab646e..cda70c5edcd4 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -619,6 +619,7 @@ bool Decl::isWeakImported() const {
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
case Function:
+ case CXXDeductionGuide:
case CXXMethod:
case CXXConstructor:
case ConstructorUsingShadow:
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a9db65a51518..2e5cec9c108f 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/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"
@@ -67,12 +68,14 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
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 +229,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 +266,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 +316,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 +343,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())
@@ -371,6 +382,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
@@ -702,9 +730,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 +742,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;
@@ -905,12 +933,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
@@ -1472,6 +1499,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 {
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 60d05f682e6e..9218eb537a60 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/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))
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index b8ebe1c568c7..5d841a197f26 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/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);
@@ -480,6 +481,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
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 +497,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 +663,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);
@@ -1043,7 +1057,10 @@ void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
prettyPrintPragmas(D->getTemplatedDecl());
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)
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a5fbb0a3baec..00a6739478bd 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/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/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 52791e51d2dc..1f8e26deda97 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/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/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 14f31d0c6b8c..d523a0f93cf6 100644
--- a/lib/AST/Expr.cpp
+++ b/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,8 +1571,9 @@ 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());
// These should not have an inheritance path.
@@ -1881,6 +1882,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();
}
@@ -2952,6 +2958,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 +3887,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/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index ad510e0070e6..6713fca04571 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/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 {
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index adb74b80b198..c035a42439a3 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/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
@@ -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/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 2c0fce91844c..2fafa4876758 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/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);
@@ -1048,16 +1072,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();
}
@@ -1273,14 +1298,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;
@@ -1404,13 +1439,24 @@ static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
EvalInfo &Info);
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
-static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info);
+static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
+ EvalInfo &Info);
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 +1504,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();
@@ -2220,7 +2259,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 +2268,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 +2293,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 +2308,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 +3242,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 +4199,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};
@@ -4691,7 +4746,10 @@ public:
case CK_AtomicToNonAtomic: {
APValue AtomicVal;
- if (!EvaluateAtomic(E->getSubExpr(), AtomicVal, Info))
+ // This does not need to be done in place even for class/array types:
+ // atomic-to-non-atomic conversion implies copying the object
+ // representation.
+ if (!Evaluate(AtomicVal, Info, E->getSubExpr()))
return false;
return DerivedSuccess(AtomicVal, E);
}
@@ -5009,6 +5067,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
@@ -5162,8 +5247,7 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
if (!EvaluateInteger(E->getIdx(), Index, Info))
return false;
- return HandleLValueArrayAdjustment(Info, E, Result, E->getType(),
- getExtValue(Index));
+ return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Index);
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
@@ -5409,6 +5493,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 +5545,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 +5679,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 +5745,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 +5769,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 +5781,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 +6345,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 +7097,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 +7155,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 +8074,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 +8133,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 +8141,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;
}
@@ -9565,10 +9698,11 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
namespace {
class AtomicExprEvaluator :
public ExprEvaluatorBase<AtomicExprEvaluator> {
+ const LValue *This;
APValue &Result;
public:
- AtomicExprEvaluator(EvalInfo &Info, APValue &Result)
- : ExprEvaluatorBaseTy(Info), Result(Result) {}
+ AtomicExprEvaluator(EvalInfo &Info, const LValue *This, APValue &Result)
+ : ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
bool Success(const APValue &V, const Expr *E) {
Result = V;
@@ -9578,7 +9712,10 @@ public:
bool ZeroInitialization(const Expr *E) {
ImplicitValueInitExpr VIE(
E->getType()->castAs<AtomicType>()->getValueType());
- return Evaluate(Result, Info, &VIE);
+ // For atomic-qualified class (and array) types in C++, initialize the
+ // _Atomic-wrapped subobject directly, in-place.
+ return This ? EvaluateInPlace(Result, Info, *This, &VIE)
+ : Evaluate(Result, Info, &VIE);
}
bool VisitCastExpr(const CastExpr *E) {
@@ -9586,15 +9723,17 @@ public:
default:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_NonAtomicToAtomic:
- return Evaluate(Result, Info, E->getSubExpr());
+ return This ? EvaluateInPlace(Result, Info, *This, E->getSubExpr())
+ : Evaluate(Result, Info, E->getSubExpr());
}
}
};
} // end anonymous namespace
-static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info) {
+static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
+ EvalInfo &Info) {
assert(E->isRValue() && E->getType()->isAtomicType());
- return AtomicExprEvaluator(Info, Result).Visit(E);
+ return AtomicExprEvaluator(Info, This, Result).Visit(E);
}
//===----------------------------------------------------------------------===//
@@ -9699,8 +9838,17 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
if (!EvaluateVoid(E, Info))
return false;
} else if (T->isAtomicType()) {
- if (!EvaluateAtomic(E, Result, Info))
- return false;
+ QualType Unqual = T.getAtomicUnqualifiedType();
+ if (Unqual->isArrayType() || Unqual->isRecordType()) {
+ LValue LV;
+ LV.set(E, Info.CurrentCall->Index);
+ APValue &Value = Info.CurrentCall->createTemporary(E, false);
+ if (!EvaluateAtomic(E, &LV, Value, Info))
+ return false;
+ } else {
+ if (!EvaluateAtomic(E, nullptr, Result, Info))
+ return false;
+ }
} else if (Info.getLangOpts().CPlusPlus11) {
Info.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
@@ -9725,10 +9873,16 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
if (E->isRValue()) {
// Evaluate arrays and record types in-place, so that later initializers can
// refer to earlier-initialized members of the object.
- if (E->getType()->isArrayType())
+ QualType T = E->getType();
+ if (T->isArrayType())
return EvaluateArray(E, This, Result, Info);
- else if (E->getType()->isRecordType())
+ else if (T->isRecordType())
return EvaluateRecord(E, This, Result, Info);
+ else if (T->isAtomicType()) {
+ QualType Unqual = T.getAtomicUnqualifiedType();
+ if (Unqual->isArrayType() || Unqual->isRecordType())
+ return EvaluateAtomic(E, &This, Result, Info);
+ }
}
// For any other type, in-place evaluation is unimportant.
@@ -9945,7 +10099,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 +10221,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());
diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp
new file mode 100644
index 000000000000..2d4d0185ff2a
--- /dev/null
+++ b/lib/AST/ExternalASTMerger.cpp
@@ -0,0 +1,185 @@
+//===- 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();
+ } 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;
+ }
+}
+
+void ForEachMatchingDC(
+ const DeclContext *DC,
+ llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers,
+ std::function<void(const ExternalASTMerger::ImporterPair &IP,
+ Source<const DeclContext *> SourceDC)>
+ Callback) {
+ for (const ExternalASTMerger::ImporterPair &IP : Importers) {
+ Source<TranslationUnitDecl *> SourceTU(
+ IP.Forward->getFromContext().getTranslationUnitDecl());
+ Source<const DeclContext *> SourceDC =
+ LookupSameContext(SourceTU, DC, *IP.Reverse);
+ if (SourceDC.get()) {
+ Callback(IP, SourceDC);
+ }
+ }
+}
+
+bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
+ return std::any_of(Decls.begin(), Decls.end(), [&C](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, [Name, &FilterFoundDecl](
+ 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, [DC, IsKindWeWant](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;
+ (void)DC;
+ }
+ }
+ });
+}
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index e3de8c5fefa2..182d38242f59 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/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/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index ab3e49d903cf..29fcdd7be924 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/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!");
}
@@ -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:
@@ -2152,10 +2158,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;
@@ -2493,9 +2501,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;
@@ -3043,6 +3048,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 +3062,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 +3150,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...)
@@ -4021,6 +4035,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";
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 05dd886adcef..00d50c0e3bdf 100644
--- a/lib/AST/Mangle.cpp
+++ b/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/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 76c368d7f04c..6e14dd055cf8 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/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!");
}
@@ -1797,10 +1800,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 +1886,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 +1957,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 +2005,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 +2026,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 +2034,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';
@@ -2474,6 +2484,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 +3018,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/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index ac2a8d354247..e7c8c16b0145 100644
--- a/lib/AST/NSAPI.cpp
+++ b/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/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp
new file mode 100644
index 000000000000..d72eebbe8e48
--- /dev/null
+++ b/lib/AST/ODRHash.cpp
@@ -0,0 +1,361 @@
+//===-- 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) {}
+void ODRHash::AddTemplateName(TemplateName Name) {}
+void ODRHash::AddTemplateArgument(TemplateArgument TA) {}
+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 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) {
+ AddQualType(D->getType());
+ Inherited::VisitValueDecl(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());
+
+ 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);
+ }
+};
+
+// 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::CXXMethod:
+ case Decl::Field:
+ case Decl::StaticAssert:
+ case Decl::TypeAlias:
+ case Decl::Typedef:
+ 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.");
+ 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 Visit(const Type *T) {
+ ID.AddInteger(T->getTypeClass());
+ Inherited::Visit(T);
+ }
+
+ void VisitType(const Type *T) {}
+
+ void VisitBuiltinType(const BuiltinType *T) {
+ ID.AddInteger(T->getKind());
+ VisitType(T);
+ }
+
+ void VisitTypedefType(const TypedefType *T) {
+ AddDecl(T->getDecl());
+ Hash.AddQualType(T->getDecl()->getUnderlyingType());
+ VisitType(T);
+ }
+};
+
+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/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp
index a28b9f3b6d64..77470a9b76d0 100644
--- a/lib/AST/OpenMPClause.cpp
+++ b/lib/AST/OpenMPClause.cpp
@@ -48,11 +48,17 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPReductionClause *>(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 +83,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:
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 697cdc3fb360..69e65f558f89 100644
--- a/lib/AST/Stmt.cpp
+++ b/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);
}
diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp
index 4a04fc211262..aade13ed3bd4 100644
--- a/lib/AST/StmtCXX.cpp
+++ b/lib/AST/StmtCXX.cpp
@@ -86,3 +86,30 @@ 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(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::ReturnStmtOnAllocFailure] =
+ Args.ReturnStmtOnAllocFailure;
+ std::copy(Args.ParamMoves.begin(), Args.ParamMoves.end(),
+ const_cast<Stmt **>(getParamMoves().data()));
+}
diff --git a/lib/AST/StmtOpenMP.cpp b/lib/AST/StmtOpenMP.cpp
index 880817a1339b..a812884cd927 100644
--- a/lib/AST/StmtOpenMP.cpp
+++ b/lib/AST/StmtOpenMP.cpp
@@ -149,6 +149,8 @@ OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
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);
@@ -201,6 +203,8 @@ OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
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);
@@ -366,6 +370,8 @@ OMPParallelForDirective *OMPParallelForDirective::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);
@@ -417,6 +423,8 @@ OMPParallelForSimdDirective *OMPParallelForSimdDirective::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);
@@ -753,6 +761,8 @@ OMPTargetParallelForDirective *OMPTargetParallelForDirective::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);
@@ -896,6 +906,8 @@ OMPTaskLoopDirective *OMPTaskLoopDirective::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);
@@ -947,6 +959,8 @@ OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::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);
@@ -997,6 +1011,8 @@ OMPDistributeDirective *OMPDistributeDirective::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);
@@ -1071,6 +1087,8 @@ 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);
@@ -1127,6 +1145,8 @@ 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);
@@ -1182,6 +1202,8 @@ OMPDistributeSimdDirective *OMPDistributeSimdDirective::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);
@@ -1236,6 +1258,8 @@ OMPTargetParallelForSimdDirective *OMPTargetParallelForSimdDirective::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);
@@ -1330,6 +1354,8 @@ OMPTeamsDistributeDirective *OMPTeamsDistributeDirective::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);
@@ -1383,6 +1409,8 @@ OMPTeamsDistributeSimdDirective *OMPTeamsDistributeSimdDirective::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);
@@ -1438,6 +1466,8 @@ 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);
@@ -1496,6 +1526,8 @@ 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);
@@ -1576,6 +1608,8 @@ OMPTargetTeamsDistributeDirective *OMPTargetTeamsDistributeDirective::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);
@@ -1634,6 +1668,8 @@ 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);
@@ -1695,6 +1731,8 @@ 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);
@@ -1753,6 +1791,8 @@ OMPTargetTeamsDistributeSimdDirective::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);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 1ba1aa40ec5c..21f5259c3ca8 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -2475,6 +2475,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/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index bcd2e96875e7..f1fbe2806b5d 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/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());
}
@@ -495,11 +623,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 +979,7 @@ void StmtProfiler::VisitOffsetOfExpr(const OffsetOfExpr *S) {
break;
case OffsetOfNode::Identifier:
- ID.AddPointer(ON.getFieldName());
+ VisitIdentifierInfo(ON.getFieldName());
break;
case OffsetOfNode::Base:
@@ -857,7 +987,7 @@ void StmtProfiler::VisitOffsetOfExpr(const OffsetOfExpr *S) {
break;
}
}
-
+
VisitExpr(S);
}
@@ -1447,7 +1577,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 +1725,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 +1831,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 +1880,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/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 099f939c7a75..e4998c37a4ef 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/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/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 0d0cd2e305be..df26233b4796 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -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,22 +2111,8 @@ 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
// Scalar types, trivially copyable class types, arrays of such types, and
@@ -2170,7 +2148,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 +2262,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
@@ -2630,8 +2600,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:
@@ -3365,6 +3333,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 +3441,7 @@ static LinkageInfo computeLinkageInfo(const Type *T) {
return LinkageInfo::external();
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
return LinkageInfo::external();
case Type::Record:
@@ -3608,7 +3578,8 @@ bool Type::canHaveNullability() const {
// auto is considered dependent when it isn't deduced.
case Type::Auto:
- return !cast<AutoType>(type.getTypePtr())->isDeduced();
+ case Type::DeducedTemplateSpecialization:
+ return !cast<DeducedType>(type.getTypePtr())->isDeduced();
case Type::Builtin:
switch (cast<BuiltinType>(type.getTypePtr())->getKind()) {
@@ -3640,7 +3611,6 @@ 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:
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 7242858f21e6..c9a268655723 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/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/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index cccc90876321..5268a2901ad9 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/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);
@@ -189,6 +189,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:
@@ -797,7 +798,14 @@ void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T,
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 +896,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);
@@ -1627,14 +1653,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::Count);
OS << "__attribute__((address_space(";
- OS << addrspace;
+ OS << addrspace - LangAS::Count;
OS << ")))";
}
}
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index d1cab80c1a53..9fa693038194 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -330,6 +330,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 +360,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 +418,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/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 56c812c34c50..59127246105d 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/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/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index d56e0e8fa1d0..2a2b3d73b5ca 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -1390,7 +1390,7 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
// Check if type is a C++ class with non-trivial destructor.
if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
- if (!CD->hasTrivialDestructor()) {
+ if (CD->hasDefinition() && !CD->hasTrivialDestructor()) {
// Add the variable to scope
Scope = createOrReuseLocalScope(Scope);
Scope->addVar(VD);
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 8c126b09d057..6d9530bf0c68 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/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/lib/Analysis/CloneDetection.cpp b/lib/Analysis/CloneDetection.cpp
index e761738214c6..5bbcbe4e5722 100644
--- a/lib/Analysis/CloneDetection.cpp
+++ b/lib/Analysis/CloneDetection.cpp
@@ -24,27 +24,27 @@
using namespace clang;
-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,8 +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.
+/// 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.
@@ -279,7 +124,9 @@ static std::string getMacroStack(SourceLocation Loc, ASTContext &Context) {
}
namespace {
-/// \brief Collects the data of a single Stmt.
+typedef unsigned DataPiece;
+
+/// 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
@@ -292,11 +139,11 @@ template <typename T>
class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> {
ASTContext &Context;
- /// \brief The data sink to which all data is forwarded.
+ /// The data sink to which all data is forwarded.
T &DataConsumer;
public:
- /// \brief Collects data of the given Stmt.
+ /// 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.
@@ -307,7 +154,7 @@ public:
// Below are utility methods for appending different data to the vector.
- void addData(CloneDetector::DataPiece Integer) {
+ void addData(DataPiece Integer) {
DataConsumer.update(
StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer)));
}
@@ -425,7 +272,7 @@ public:
})
DEF_ADD_DATA(DeclStmt, {
auto numDecls = std::distance(S->decl_begin(), S->decl_end());
- addData(static_cast<CloneDetector::DataPiece>(numDecls));
+ addData(static_cast<DataPiece>(numDecls));
for (const Decl *D : S->decls()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
addData(VD->getType());
@@ -454,199 +301,131 @@ public:
};
} // end anonymous namespace
-namespace {
-/// Generates CloneSignatures for a set of statements and stores the results in
-/// a CloneDetector object.
-class CloneSignatureGenerator {
+void CloneDetector::analyzeCodeBody(const Decl *D) {
+ assert(D);
+ assert(D->hasBody());
- CloneDetector &CD;
- ASTContext &Context;
+ Sequences.push_back(StmtSequence(D->getBody(), D));
+}
- /// \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;
- }
+/// 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;
+}
- // 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);
+/// 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;
- // 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 (StmtSequence &Stmt : Group) {
+ if (!containsAnyInGroup(Stmt, OtherGroup))
+ return false;
+ }
+ 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);
+void OnlyLargestCloneConstraint::constrain(
+ std::vector<CloneDetector::CloneGroup> &Result) {
+ std::vector<unsigned> IndexesToRemove;
- // 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)));
+ // 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;
- // 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);
+ if (containsGroup(Result[j], Result[i])) {
+ IndexesToRemove.push_back(i);
+ break;
+ }
}
+ }
- // 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);
+ // 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);
+ }
+}
- // Create the final hash code for the current signature.
- llvm::MD5::MD5Result HashResult;
- Hash.final(HashResult);
+static size_t createHash(llvm::MD5 &Hash) {
+ size_t HashCode;
- // 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)));
+ // Create the final hash code for the current Stmt.
+ llvm::MD5::MD5Result HashResult;
+ Hash.final(HashResult);
- // Save the signature for the current statement in the CloneDetector object.
- CD.add(StmtSequence(S, Context), Signature);
+ // 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)));
- return Signature;
- }
+ return HashCode;
+}
- /// \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) {
+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();
- // FIXME: This function has quadratic runtime right now. Check if skipping
- // this function for too long CompoundStmts is an option.
+ StmtDataCollector<llvm::MD5>(S, Context, Hash);
- // The length of the sub-sequence. We don't need to handle sequences with
- // the length 1 as they are already handled in CollectData().
+ auto CS = dyn_cast<CompoundStmt>(S);
+ SmallVector<size_t, 8> ChildHashes;
+
+ 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);
+ }
+
+ if (CS) {
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;
-
+ llvm::MD5 Hash;
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),
+ size_t ChildHash = ChildHashes[i];
+ Hash.update(StringRef(reinterpret_cast<char *>(&ChildHash),
sizeof(ChildHash)));
}
-
- // 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);
+ StmtsByHash.push_back(std::make_pair(
+ createHash(Hash), StmtSequence(CS, D, Pos, Pos + Length)));
}
}
}
-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 +437,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 +449,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 +472,272 @@ 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 to
+ // 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/lib/Analysis/OSLog.cpp b/lib/Analysis/OSLog.cpp
index 3e13a153c65f..b2983932ea22 100644
--- a/lib/Analysis/OSLog.cpp
+++ b/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/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index a2f3203762f7..60724ea60b25 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/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/lib/Analysis/ThreadSafetyTIL.cpp b/lib/Analysis/ThreadSafetyTIL.cpp
index 2923f7e66a61..83aa90435e2a 100644
--- a/lib/Analysis/ThreadSafetyTIL.cpp
+++ b/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/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 8929ec30ff7b..2feb31851cfe 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -74,6 +74,7 @@ add_clang_library(clangBasic
FileSystemStatCache.cpp
IdentifierTable.cpp
LangOptions.cpp
+ MemoryBufferCache.cpp
Module.cpp
ObjCRuntime.cpp
OpenMPKinds.cpp
@@ -89,6 +90,7 @@ add_clang_library(clangBasic
VersionTuple.cpp
VirtualFileSystem.cpp
Warnings.cpp
+ XRayLists.cpp
${version_inc}
)
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 7529c475d6b9..350d5477751c 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/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"
@@ -131,13 +132,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,
@@ -157,27 +158,94 @@ void DiagnosticsEngine::ReportDelayed() {
DelayedDiagArg2.clear();
}
-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 +255,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);
- 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);
+ 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;
}
- // 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,
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 3c370f67fa32..e0580af45b50 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/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?
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 50050d0a519b..0c10b5f4d14c 100644
--- a/lib/Basic/FileManager.cpp
+++ b/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/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index af424cd92390..74c85376c7db 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/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() == '_')
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index ff10a773a97c..c8a774311efe 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -33,6 +33,8 @@ void LangOptions::resetNonModularOptions() {
// sanitizer options (this affects __has_feature(address_sanitizer) etc).
Sanitize.clear();
SanitizerBlacklistFiles.clear();
+ XRayAlwaysInstrumentFiles.clear();
+ XRayNeverInstrumentFiles.clear();
CurrentModule.clear();
IsHeaderFile = false;
diff --git a/lib/Basic/MemoryBufferCache.cpp b/lib/Basic/MemoryBufferCache.cpp
new file mode 100644
index 000000000000..c1fc571ec9b3
--- /dev/null
+++ b/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/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 80bbc24f3db3..a6fd931cb174 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -27,7 +27,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),
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 905c3693d378..5a8bb61eaadf 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -863,3 +863,76 @@ bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) {
Kind == OMPD_target_teams_distribute_parallel_for_simd ||
Kind == OMPD_target_teams_distribute_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/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 380ca373e69b..156aa0b11f7d 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -1136,6 +1136,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 +1145,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;
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index b1b01e5f584f..e19404dc54cb 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -282,8 +282,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)
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 1a95ff26816e..a457f6deee75 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -545,6 +545,8 @@ 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)
@@ -552,11 +554,11 @@ public:
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 +888,7 @@ class PPCTargetInfo : public TargetInfo {
std::string CPU;
// Target cpu features.
+ bool HasAltivec;
bool HasVSX;
bool HasP8Vector;
bool HasP8Crypto;
@@ -901,9 +904,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 +934,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 +1175,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 +1237,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 +1374,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 +1397,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 +1412,6 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// __RSQRTEF__
// _SOFT_DOUBLE_
// __NO_LWSYNC__
- // __HAVE_BSWAP__
- // __LONGDOUBLE128
// __CMODEL_MEDIUM__
// __CMODEL_LARGE__
// _CALL_SYSV
@@ -1481,6 +1517,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 +1531,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 +1762,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 +1774,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 +2033,25 @@ 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 AMDGPUPrivateIsZeroMap = {
+ 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 AMDGPUGenericIsZeroMap = {
+ 0, // 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 +2061,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 +2107,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,17 +2135,21 @@ 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);
+ (IsGenericZero ? DataLayoutStringSIGenericIsZero :
+ DataLayoutStringSIPrivateIsZero)
+ : DataLayoutStringR600);
+ assert(DataLayout->getAllocaAddrSpace() == AS.Private);
- AddrSpaceMap = &AMDGPUAddrSpaceMap;
+ AddrSpaceMap = IsGenericZero ? &AMDGPUGenericIsZeroMap :
+ &AMDGPUPrivateIsZeroMap;
UseAddrSpaceMapMangling = true;
}
@@ -2066,14 +2157,10 @@ public:
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 getMaxPointerWidth() const override {
@@ -2113,15 +2200,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 +2294,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 +2338,33 @@ public:
return LangAS::opencl_constant;
}
+ /// \returns Target specific vtbl ptr address space.
+ unsigned getVtblPtrAddressSpace() const override {
+ // \todo: We currently have address spaces defined in AMDGPU Backend. It
+ // would be nice if we could use it here instead of using bare numbers (same
+ // applies to getDWARFAddressSpace).
+ return 2; // 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 +2379,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 +2462,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:
@@ -2489,11 +2610,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;
@@ -3067,8 +3187,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,44 +3195,43 @@ 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);
@@ -3173,7 +3291,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 +3306,7 @@ bool X86TargetInfo::initFeatureMap(
setFeatureEnabledImpl(Features, "bmi", true);
setFeatureEnabledImpl(Features, "f16c", true);
setFeatureEnabledImpl(Features, "xsaveopt", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_BTVER1:
setFeatureEnabledImpl(Features, "ssse3", true);
setFeatureEnabledImpl(Features, "sse4a", true);
@@ -3205,6 +3323,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,17 +3348,17 @@ 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);
@@ -3560,14 +3679,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)
@@ -3885,6 +4002,18 @@ 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) {
@@ -3971,6 +4100,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 +4114,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 +4131,6 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("sse4.2", SSELevel >= SSE42)
.Case("sse4a", XOPLevel >= SSE4A)
.Case("tbm", HasTBM)
- .Case("umip", HasUMIP)
.Case("x86", true)
.Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
.Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
@@ -5056,6 +5184,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 +5274,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;
@@ -5925,7 +6057,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
@@ -5960,8 +6093,9 @@ 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)
+ if (Triple.getOS() == llvm::Triple::Linux)
+ this->MCountName = "\01_mcount";
+ else if (Triple.getOS() == llvm::Triple::UnknownOS)
this->MCountName = Opts.EABIVersion == "gnu" ? "\01_mcount" : "mcount";
}
@@ -6408,6 +6542,7 @@ public:
.Case("hexagonv5", "5")
.Case("hexagonv55", "55")
.Case("hexagonv60", "60")
+ .Case("hexagonv62", "62")
.Default(nullptr);
}
@@ -6452,6 +6587,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")) {
@@ -7037,6 +7175,15 @@ public:
Builder.defineMacro("__zarch__");
Builder.defineMacro("__LONG_DOUBLE_128__");
+ const std::string ISARev = llvm::StringSwitch<std::string>(CPU)
+ .Cases("arch8", "z10", "8")
+ .Cases("arch9", "z196", "9")
+ .Cases("arch10", "zEC12", "10")
+ .Cases("arch11", "z13", "11")
+ .Default("");
+ if (!ISARev.empty())
+ Builder.defineMacro("__ARCH__", ISARev);
+
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,6 +7191,8 @@ public:
if (HasTransactionalExecution)
Builder.defineMacro("__HTM__");
+ if (HasVector)
+ Builder.defineMacro("__VX__");
if (Opts.ZVector)
Builder.defineMacro("__VEC__", "10301");
}
@@ -7268,6 +7417,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
@@ -7434,6 +7584,8 @@ class MipsTargetInfo : public TargetInfo {
bool IsMicromips;
bool IsNan2008;
bool IsSingleFloat;
+ bool IsNoABICalls;
+ bool CanUseBSDABICalls;
enum MipsFloatABI {
HardFloat, SoftFloat
} FloatABI;
@@ -7449,8 +7601,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), HasFP64(false) {
TheCXXABI.set(TargetCXXABI::GenericMIPS);
setABI((getTriple().getArch() == llvm::Triple::mips ||
@@ -7459,6 +7612,9 @@ public:
: "n64");
CPU = ABI == "o32" ? "mips32r2" : "mips64r2";
+
+ CanUseBSDABICalls = Triple.getOS() == llvm::Triple::FreeBSD ||
+ Triple.getOS() == llvm::Triple::OpenBSD;
}
bool isNaN2008Default() const {
@@ -7535,7 +7691,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 +7799,12 @@ public:
} else
llvm_unreachable("Invalid ABI.");
+ if (!IsNoABICalls) {
+ Builder.defineMacro("__mips_abicalls");
+ if (CanUseBSDABICalls)
+ Builder.defineMacro("__ABICALLS__");
+ }
+
Builder.defineMacro("__REGISTER_PREFIX__", "");
switch (FloatABI) {
@@ -7853,6 +8019,8 @@ public:
IsNan2008 = true;
else if (Feature == "-nan2008")
IsNan2008 = false;
+ else if (Feature == "+noabicalls")
+ IsNoABICalls = true;
}
setDataLayout();
@@ -8216,6 +8384,7 @@ const Builtin::Info Le64TargetInfo::BuiltinInfo[] = {
};
static const unsigned SPIRAddrSpaceMap[] = {
+ 0, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
@@ -8435,6 +8604,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 +8893,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 +8944,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 +9012,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 +9087,8 @@ 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);
default:
return new AArch64leTargetInfo(Triple, Opts);
}
@@ -8604,8 +9119,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 +9155,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:
@@ -8879,8 +9390,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:
@@ -8976,11 +9485,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/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 97e75a9cd45e..a1a67c2bc144 100644
--- a/lib/Basic/Version.cpp
+++ b/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/trunk/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp
index 50fcb22faf53..f5db717866a9 100644
--- a/lib/Basic/VirtualFileSystem.cpp
+++ b/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/lib/Basic/XRayLists.cpp b/lib/Basic/XRayLists.cpp
new file mode 100644
index 000000000000..dccf3baa75e2
--- /dev/null
+++ b/lib/Basic/XRayLists.cpp
@@ -0,0 +1,53 @@
+//===--- 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))
+ 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/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index ac31dfdaf3e4..c0be60ef53bc 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/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"
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index d2ce6ea48e41..855d6795b9d6 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -61,6 +61,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 +76,6 @@ class EmitAssemblyHelper {
std::unique_ptr<raw_pwrite_stream> OS;
-private:
TargetIRAnalysis getTargetIRAnalysis() const {
if (TM)
return TM->getTargetIRAnalysis();
@@ -262,7 +264,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 +294,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:
+ Options.AllowFPOpFusion = llvm::FPOpFusion::Strict;
+ 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.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.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);
+}
+
void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
legacy::FunctionPassManager &FPM) {
// Handle disabling of all LLVM passes, where we want to preserve the
@@ -316,8 +452,13 @@ 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;
@@ -334,16 +475,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 +592,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;
@@ -495,126 +633,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 +656,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
@@ -683,14 +703,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:
@@ -779,7 +816,24 @@ 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;
+
+ // 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()) ?
+ Optional<PGOOptions>(PGOOpt) : None);
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
@@ -861,8 +915,31 @@ 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 with a
+ // summary.
+ for (BitcodeModule &BM : *BMsOrErr) {
+ Expected<bool> HasSummary = BM.hasSummary();
+ if (HasSummary && *HasSummary)
+ 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) {
+ 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<std::map<GlobalValue::GUID, GlobalValueSummary *>>
ModuleToDefinedGVSummaries;
CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
@@ -897,32 +974,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 +990,35 @@ 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);
+ 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)) {
@@ -965,7 +1054,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 +1086,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 +1099,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/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index 9287e46127bd..28e20b53d656 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -1181,7 +1181,7 @@ RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
if (LVal.isBitField())
return CGF.EmitLoadOfBitfieldLValue(
LValue::MakeBitfield(addr, LVal.getBitFieldInfo(), LVal.getType(),
- LVal.getAlignmentSource()));
+ LVal.getAlignmentSource()), loc);
if (LVal.isVectorElt())
return CGF.EmitLoadOfLValue(
LValue::MakeVectorElt(addr, LVal.getVectorIdx(), LVal.getType(),
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index b250b9a32b18..1a57b3e6608d 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/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,8 +611,8 @@ 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;
@@ -634,7 +639,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 +723,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(cast<llvm::PointerType>(
+ CGM.getNSConcreteStackBlock()->getType()),
+ QualType(getContext().VoidPtrTy));
isa = llvm::ConstantExpr::getBitCast(isa, VoidPtrTy);
// Build the block descriptor.
@@ -906,9 +916,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;
}
@@ -976,21 +985,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 +1126,12 @@ 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(cast<llvm::PointerType>(
+ CGM.getNSConcreteGlobalBlock()->getType()),
+ QualType(CGM.getContext().VoidPtrTy)));
// __flags
BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE;
@@ -1114,16 +1148,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 +1192,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,6 +1237,15 @@ 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 accomodate 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),
@@ -1323,23 +1373,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);
@@ -1399,78 +1528,28 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign);
dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
+ SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures;
+ findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures,
+ computeCopyInfoForBlockCapture);
- 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
-
- } 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 +1570,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 +1578,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 +1602,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);
///
@@ -1570,79 +1697,39 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
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();
-
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
- if (capture.isConstant()) continue;
-
- BlockFieldFlags flags;
- const CXXDestructorDecl *dtor = nullptr;
+ SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures;
+ findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures,
+ computeDestroyInfoForBlockCapture);
- 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);
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index b3d02f1f51c6..6ea0a325a429 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/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));
@@ -2195,16 +2255,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 +2271,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 +2291,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 +2329,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 +2548,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 +2585,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 +2622,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};
@@ -2596,26 +2663,30 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// 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:
@@ -7115,6 +7186,13 @@ 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 ||
@@ -7321,7 +7399,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 +7491,21 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_storesd128_mask: {
return EmitX86MaskedStore(*this, Ops, 16);
}
+
+ 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:
@@ -7922,6 +8020,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;
+ }
}
}
@@ -8326,6 +8463,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 +8536,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"));
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
index 83febcb4af8c..813cd7400186 100644
--- a/lib/CodeGen/CGCUDANV.cpp
+++ b/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"
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 59010f4407c2..0f3141ab76d0 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/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/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index d53fd4cb63b2..7b912e3aca57 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/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/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index c7c61e0c8ecb..8af32055fc4c 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -101,39 +101,64 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
FTNP->getExtInfo(), {}, RequiredArgs(0));
}
+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 paramaters 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,
@@ -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);
@@ -680,7 +719,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;
@@ -1620,15 +1659,113 @@ 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);
+ llvm::AttributeList AS = llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs);
+ F.addAttributes(llvm::AttributeList::FunctionIndex, AS);
+}
+
void CodeGenModule::ConstructAttributeList(
StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
AttributeListType &PAL, 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 +1776,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>())
@@ -1679,7 +1816,6 @@ void CodeGenModule::ConstructAttributeList(
if (TargetDecl->hasAttr<ReturnsNonNullAttr>())
RetAttrs.addAttribute(llvm::Attribute::NonNull);
- HasAnyX86InterruptAttr = TargetDecl->hasAttr<AnyX86InterruptAttr>();
HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
Optional<unsigned> NumElemsParam;
@@ -1691,86 +1827,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
@@ -1819,21 +1888,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();
@@ -1878,8 +1932,8 @@ void CodeGenModule::ConstructAttributeList(
// Attach return attributes.
if (RetAttrs.hasAttributes()) {
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), llvm::AttributeSet::ReturnIndex, RetAttrs));
+ PAL.push_back(llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeList::ReturnIndex, RetAttrs));
}
bool hasUsedSRet = false;
@@ -1891,7 +1945,7 @@ void CodeGenModule::ConstructAttributeList(
hasUsedSRet = true;
if (RetAI.getInReg())
SRETAttrs.addAttribute(llvm::Attribute::InReg);
- PAL.push_back(llvm::AttributeSet::get(
+ PAL.push_back(llvm::AttributeList::get(
getLLVMContext(), IRFunctionArgs.getSRetArgNo() + 1, SRETAttrs));
}
@@ -1899,7 +1953,7 @@ void CodeGenModule::ConstructAttributeList(
if (IRFunctionArgs.hasInallocaArg()) {
llvm::AttrBuilder Attrs;
Attrs.addAttribute(llvm::Attribute::InAlloca);
- PAL.push_back(llvm::AttributeSet::get(
+ PAL.push_back(llvm::AttributeList::get(
getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs));
}
@@ -1914,7 +1968,7 @@ void CodeGenModule::ConstructAttributeList(
// Add attribute for padding argument, if necessary.
if (IRFunctionArgs.hasPaddingArg(ArgNo)) {
if (AI.getPaddingInReg())
- PAL.push_back(llvm::AttributeSet::get(
+ PAL.push_back(llvm::AttributeList::get(
getLLVMContext(), IRFunctionArgs.getPaddingArgNo(ArgNo) + 1,
llvm::Attribute::InReg));
}
@@ -2031,17 +2085,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));
+ PAL.push_back(llvm::AttributeList::get(getLLVMContext(),
+ FirstIRArg + i + 1, Attrs));
}
}
assert(ArgNo == FI.arg_size());
if (FuncAttrs.hasAttributes())
- PAL.push_back(llvm::
- AttributeSet::get(getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- FuncAttrs));
+ PAL.push_back(llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs));
}
/// An argument came in as a promoted argument; demote it back to its
@@ -2152,8 +2204,8 @@ 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::AttributeList::get(getLLVMContext(), AI->getArgNo() + 1,
+ llvm::Attribute::NoAlias));
}
// Track if we received the parameter as a pointer (indirect, byval, or
@@ -2244,9 +2296,9 @@ 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::AttributeList::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NonNull));
QualType OTy = PVD->getOriginalType();
if (const auto *ArrTy =
@@ -2263,12 +2315,12 @@ 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->addAttr(llvm::AttributeList::get(
+ getLLVMContext(), AI->getArgNo() + 1, Attrs));
} else if (getContext().getTargetAddressSpace(ETy) == 0) {
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NonNull));
+ AI->addAttr(llvm::AttributeList::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NonNull));
}
}
} else if (const auto *ArrTy =
@@ -2278,9 +2330,9 @@ 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::AttributeList::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NonNull));
}
const auto *AVAttr = PVD->getAttr<AlignValueAttr>();
@@ -2298,15 +2350,14 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::AttrBuilder Attrs;
Attrs.addAlignmentAttr(Alignment);
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1, Attrs));
+ AI->addAttr(llvm::AttributeList::get(getLLVMContext(),
+ AI->getArgNo() + 1, Attrs));
}
}
if (Arg->getType().isRestrictQualified())
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NoAlias));
+ AI->addAttr(llvm::AttributeList::get(
+ getLLVMContext(), AI->getArgNo() + 1, llvm::Attribute::NoAlias));
// LLVM expects swifterror parameters to be used in very restricted
// ways. Copy the value into a less-restricted temporary.
@@ -2858,19 +2909,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, EndLoc);
Ret = Builder.CreateRet(RV);
} else {
Ret = Builder.CreateRetVoid();
@@ -2880,6 +2919,63 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
Ret->setDebugLoc(std::move(RetDbgLoc));
}
+void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV,
+ SourceLocation EndLoc) {
+ // 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);
+
+ llvm::BasicBlock *Check = nullptr;
+ llvm::BasicBlock *NoCheck = nullptr;
+ if (requiresReturnValueNullabilityCheck()) {
+ // Before doing the nullability check, make sure that the preconditions for
+ // the check are met.
+ Check = createBasicBlock("nullcheck");
+ NoCheck = createBasicBlock("no.nullcheck");
+ Builder.CreateCondBr(RetValNullabilityPrecondition, Check, NoCheck);
+ EmitBlock(Check);
+ }
+
+ // Now do the null check. If the returns_nonnull attribute is present, this
+ // is done unconditionally.
+ llvm::Value *Cond = Builder.CreateIsNotNull(RV);
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(EndLoc), EmitCheckSourceLocation(AttrLoc),
+ };
+ EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None);
+
+ if (requiresReturnValueNullabilityCheck())
+ EmitBlock(NoCheck);
+}
+
static bool isInAllocaArgument(CGCXXABI &ABI, QualType type) {
const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
return RD && ABI.getRecordArgABI(RD) == CGCXXABI::RAA_DirectInMemory;
@@ -3188,50 +3284,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 +3351,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 +3389,20 @@ 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();
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) {
@@ -3571,12 +3710,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");
}
@@ -3977,8 +4118,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Callee.getAbstractInfo(),
AttributeList, CallingConv,
/*AttrOnCallSite=*/true);
- llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
- AttributeList);
+ llvm::AttributeList Attrs =
+ llvm::AttributeList::get(getLLVMContext(), AttributeList);
// Apply some call-site-specific attributes.
// TODO: work this into building the attribute set.
@@ -3989,15 +4130,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 +4154,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();
@@ -4210,6 +4350,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/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 031ce831cb37..97221e20c195 100644
--- a/lib/CodeGen/CGCall.h
+++ b/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,28 @@ 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; }
+typedef SmallVector<llvm::AttributeList, 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; }
};
/// All available information about a concrete callee.
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 05d056739524..7ba03a0d42dd 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -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;
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 3666858e63d2..437ab7dd4649 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -418,11 +418,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 +436,41 @@ 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;
+ 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 +609,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/lib/CodeGen/CGCoroutine.cpp b/lib/CodeGen/CGCoroutine.cpp
index 2fdb1279ece9..0ef680ef6609 100644
--- a/lib/CodeGen/CGCoroutine.cpp
+++ b/lib/CodeGen/CGCoroutine.cpp
@@ -12,28 +12,58 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "llvm/ADT/ScopeExit.h"
#include "clang/AST/StmtCXX.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;
+
// 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 +89,250 @@ 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.
+//
+static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
+ CoroutineSuspendExpr const &S,
+ AwaitKind Kind, AggValueSlot aggSlot,
+ bool ignoreResult) {
+ 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);
+ return CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
+}
+
+RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E,
+ AggValueSlot aggSlot,
+ bool ignoreResult) {
+ return emitSuspendExpression(*this, *CurCoro.Data, E,
+ CurCoro.Data->CurrentAwaitKind, aggSlot,
+ ignoreResult);
+}
+RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E,
+ AggValueSlot aggSlot,
+ bool ignoreResult) {
+ return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield,
+ aggSlot, ignoreResult);
+}
+
+void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) {
+ ++CurCoro.Data->CoreturnCount;
+ EmitStmt(S.getPromiseCall());
+ EmitBranchThroughCleanup(CurCoro.Data->FinalJD);
+}
+
+// For WinEH exception representation backend need 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;
+
+ // TODO: Wrap deallocate in if(coro.free(...)) Deallocate.
+ void Emit(CodeGenFunction &CGF, Flags) override {
+ // Note: That deallocation will be emitted twice: once for a normal exit and
+ // once for exceptional exit. This usage is safe because Deallocate does not
+ // contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr()
+ // builds a single call to a deallocation function which is safe to emit
+ // multiple times.
+ CGF.EmitStmt(Deallocate);
+ }
+ explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {}
+};
+}
+
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 *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;
+
+ auto *AllocateCall = EmitScalarExpr(S.getAllocate());
+
+ // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
+ if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
+ auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure");
+ auto *InitBB = createBasicBlock("coro.init");
+
+ // See if allocation was successful.
+ auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy);
+ auto *Cond = Builder.CreateICmpNE(AllocateCall, NullPtr);
+ Builder.CreateCondBr(Cond, InitBB, RetOnFailureBB);
+
+ // If not, return OnAllocFailure object.
+ EmitBlock(RetOnFailureBB);
+ EmitStmt(RetOnAllocFailure);
+
+ EmitBlock(InitBB);
+ }
+
+ CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB);
+ {
+ CodeGenFunction::RunCleanupsScope ResumeScope(*this);
+ EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate());
+
+ EmitStmt(S.getPromiseDeclStmt());
+
+ EHStack.pushCleanup<CallCoroEnd>(EHCleanup);
+
+ CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
+
+ // FIXME: Emit initial suspend and more before the body.
+
+ CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
+ EmitStmt(S.getBody());
+
+ // See if we need to generate final suspend.
+ const bool CanFallthrough = Builder.GetInsertBlock();
+ const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0;
+ if (CanFallthrough || HasCoreturns) {
+ EmitBlock(FinalBB);
+ // FIXME: Emit final suspend.
+ }
+ }
+
+ EmitBlock(RetBB);
+ llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
+ Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()});
- EmitScalarExpr(S.getAllocate());
- // FIXME: Emit the rest of the coroutine.
- EmitStmt(S.getDeallocate());
+ // FIXME: Emit return for the coroutine return object.
}
// Emit coroutine intrinsic and patch up arguments of the token type.
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 12a68036b09c..818b51543d30 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/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())
@@ -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()) {
@@ -509,7 +533,8 @@ void CGDebugInfo::CreateCompileUnit() {
Checksum),
Producer, LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers,
CGM.getCodeGenOpts().SplitDwarfFile, EmissionKind, 0 /* DWOid */,
- CGM.getCodeGenOpts().SplitDwarfInlining);
+ CGM.getCodeGenOpts().SplitDwarfInlining,
+ CGM.getCodeGenOpts().DebugInfoForProfiling);
}
llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
@@ -581,8 +606,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 +816,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,
@@ -1608,8 +1633,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 +1678,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 +1748,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 +1814,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 +2057,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 +2460,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 +2518,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 +2556,17 @@ void CGDebugInfo::completeTemplateDefinition(
const ClassTemplateSpecializationDecl &SD) {
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
+ completeUnusedClass(SD);
+}
+
+void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) {
+ if (DebugKind <= codegenoptions::DebugLineTablesOnly)
+ return;
- completeClassData(&SD);
+ 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) {
@@ -2618,6 +2692,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:
@@ -2774,9 +2849,10 @@ 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();
@@ -2844,28 +2920,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 +2963,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 +3244,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 = 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);
+ setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt());
+}
+
void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
// Update our current location
setLocation(Loc);
@@ -3155,7 +3274,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 +3286,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;
@@ -3316,13 +3450,16 @@ 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());
+ unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType());
+ AppendAddressSpaceXDeref(AddressSpace, Expr);
+
// 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
@@ -3360,9 +3497,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
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());
+ DBuilder.insertDeclare(
+ Storage, D, DBuilder.createExpression(Expr),
+ llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
+ Builder.GetInsertBlock());
return;
} else if (isa<VariableArrayType>(VD->getType()))
Expr.push_back(llvm::dwarf::DW_OP_deref);
@@ -3393,9 +3531,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 +3550,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());
}
@@ -3492,7 +3631,8 @@ 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);
if (InsertPoint)
DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
InsertPoint);
@@ -3660,12 +3800,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 +3888,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);
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index ac2e8dd2e0a4..5050ca0ad3fa 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/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;
@@ -292,6 +293,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 +330,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,6 +357,11 @@ 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);
@@ -409,9 +435,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 +529,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 +667,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/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 0a88b2310beb..0f959043a22e 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -50,6 +50,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:
@@ -671,6 +672,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 +700,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 +789,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.
@@ -1022,11 +1047,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());
@@ -1083,6 +1118,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 +1414,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 +1725,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, Int8PtrTy);
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, Int8PtrTy);
return LifetimeEndFn;
}
@@ -1869,6 +1905,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/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index f56e18216931..f61d60a63a6a 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/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();
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index f908bf2b3b0a..ca1535182ec1 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/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,
@@ -1666,23 +1666,12 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
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;
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index e5e34a5f3ed6..265ef27a46b0 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -71,7 +71,8 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
/// block.
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
const Twine &Name) {
- return new llvm::AllocaInst(Ty, nullptr, Name, AllocaInsertPt);
+ return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
+ nullptr, Name, AllocaInsertPt);
}
/// CreateDefaultAlignTempAlloca - This creates an alloca with the
@@ -534,7 +535,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;
@@ -552,7 +554,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
TCK == TCK_UpcastToVirtualBase;
if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
- !SkipNullCheck) {
+ !SkippedChecks.has(SanitizerKind::Null)) {
// The glvalue must not be an empty glvalue.
llvm::Value *IsNonNull = Builder.CreateIsNotNull(Ptr);
@@ -568,7 +570,9 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
}
}
- 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 +582,24 @@ 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) {
llvm::Value *Align =
Builder.CreateAnd(Builder.CreatePtrToInt(Ptr, IntPtrTy),
llvm::ConstantInt::get(IntPtrTy, AlignVal - 1));
@@ -624,6 +630,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) &&
@@ -947,15 +954,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 +1072,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.getAlignmentSource(),
+ 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:
@@ -1265,6 +1316,53 @@ 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,
@@ -1273,26 +1371,28 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
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);
+ }
}
}
@@ -1317,35 +1417,9 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
false /*ConvertTypeToTag*/);
}
- 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);
@@ -1386,24 +1460,25 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
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 = 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");
+ }
}
}
@@ -1487,10 +1562,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 +1591,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);
}
@@ -2545,8 +2621,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 +2785,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
@@ -2821,7 +2915,7 @@ 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;
@@ -3335,7 +3429,14 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
AlignmentSource AlignSource;
Address Addr = EmitPointerWithAlignment(BaseExpr, &AlignSource);
QualType PtrTy = BaseExpr->getType()->getPointeeType();
- EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy);
+ 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, AlignSource);
} else
BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 009244784e50..49bbb4808eaa 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/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());
@@ -1267,7 +1274,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/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 71c8fb8b7ae3..d02f074dd605 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/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);
}
@@ -290,10 +300,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 +440,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 +680,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 +1280,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");
@@ -1560,7 +1584,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);
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 59bc9cdbc056..980972370dc2 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/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/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 1b85c45cd4be..a64303831171 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "CGCleanup.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
@@ -24,6 +25,7 @@
#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"
@@ -47,7 +49,7 @@ struct BinOpInfo {
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.
};
@@ -58,6 +60,75 @@ 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 (const auto *UO = dyn_cast<UnaryOperator>(Op.E))
+ return IsWidenedIntegerOp(Ctx, UO->getSubExpr());
+
+ 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;
+
+ // We usually don't need overflow checks for binary operations with widened
+ // operands. Multiplication with promoted unsigned operands is a special case.
+ if ((Op.Opcode != BO_Mul && Op.Opcode != BO_MulAssign) ||
+ !LHSTy->isUnsignedIntegerType() || !RHSTy->isUnsignedIntegerType())
+ return true;
+
+ // The overflow check can be skipped 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 +292,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 +380,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 +503,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 +558,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.
@@ -1616,6 +1715,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 +1736,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 +1754,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");
@@ -1891,7 +2002,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 +2223,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 +2243,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 +2374,10 @@ 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())) {
llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
llvm::Value *IntMin =
@@ -2324,12 +2437,12 @@ 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()) {
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())
@@ -2577,12 +2690,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.
@@ -2616,12 +2724,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 +2740,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 +2759,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");
@@ -2751,8 +2867,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 +2883,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 +3156,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 +3447,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 +3613,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 +3627,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;
diff --git a/lib/CodeGen/CGCUDABuiltin.cpp b/lib/CodeGen/CGGPUBuiltin.cpp
index 44dd003757ad..48156b1b26b7 100644
--- a/lib/CodeGen/CGCUDABuiltin.cpp
+++ b/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/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 932b8a129e6e..3a09a15dbc15 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/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,22 @@ 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);
+ Address Addr(Constant, Context.getTypeAlignInChars(IdTy));
+ LValue LV = MakeAddrLValue(Addr, IdTy);
+ return Builder.CreateBitCast(EmitLoadOfScalar(LV, E->getLocStart()),
+ 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();
@@ -427,7 +439,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 +1328,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 +1481,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 +1513,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 +1814,49 @@ 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)) {
+ llvm::AttrBuilder B;
+ B.addAttribute(llvm::Attribute::Returned);
+
+ F->arg_begin()->addAttr(llvm::AttributeList::get(F->getContext(), 1, B));
}
}
- return fn;
+ return RTF;
}
/// Perform an operation having the signature
@@ -1832,7 +1867,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 =
@@ -3239,7 +3275,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);
@@ -3375,5 +3411,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/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index fa2b3d81e29a..9f6ccb4b5d26 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/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"
@@ -2207,7 +2207,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/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 7219592fffcd..43b347ce353f 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/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, ...)
@@ -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:
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index 9062936fdd14..db02c631c9e6 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/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/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index 40252171368b..874b6a69e513 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/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"
@@ -842,12 +842,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 +857,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,
@@ -2958,7 +2974,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));
@@ -3561,7 +3577,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,
@@ -3764,9 +3780,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 +4020,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);
@@ -4241,12 +4255,10 @@ 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);
@@ -4329,11 +4341,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 +4365,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 +4513,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 +4579,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 +4589,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 {
@@ -4874,25 +4891,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 +4947,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
@@ -5984,8 +6075,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 +6112,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 +6212,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 +6232,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;
}
@@ -6271,8 +6398,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 +6445,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 +6523,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/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index 61ddc702ed24..7901a6b7a8fc 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -527,6 +527,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 +536,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);
@@ -880,6 +893,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 +955,18 @@ 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);
/// \brief Emit code for 'taskwait' directive.
virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc);
@@ -991,7 +1034,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/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
index 6a6d832e33cd..c3391d087b75 100644
--- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
+++ b/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,74 @@ 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->addFnAttr(llvm::Attribute::AlwaysInline);
return OutlinedFun;
}
@@ -525,7 +891,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 +902,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 +933,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 +964,1289 @@ 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
+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, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.VoidPtrTy);
+ // Base address of the scratchpad array, with each element storing a
+ // Reduce list per team.
+ ImplicitParamDecl ScratchPadArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.VoidPtrTy);
+ // A source index into the scratchpad array.
+ ImplicitParamDecl IndexArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, Int32Ty);
+ // Row width of an element in the scratchpad array, typically
+ // the number of teams.
+ ImplicitParamDecl WidthArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, Int32Ty);
+ // 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, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, Int32Ty);
+
+ 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
+///
+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, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.VoidPtrTy);
+ // Base address of the scratchpad array, with each element storing a
+ // Reduce list per team.
+ ImplicitParamDecl ScratchPadArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.VoidPtrTy);
+ // A destination index into the scratchpad array, typically the team
+ // identifier.
+ ImplicitParamDecl IndexArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, Int32Ty);
+ // Row width of an element in the scratchpad array, typically
+ // the number of teams.
+ ImplicitParamDecl WidthArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, Int32Ty);
+
+ 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, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.VoidPtrTy);
+ // 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, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr,
+ C.getIntTypeForBitwidth(32, /* Signed */ true));
+ 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, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.VoidPtrTy);
+ // Current lane id; could be logical.
+ ImplicitParamDecl LaneIDArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.ShortTy);
+ // Offset of the remote source lane relative to the current lane.
+ ImplicitParamDecl RemoteLaneOffsetArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.ShortTy);
+ // Algorithm version. This is expected to be known at compile time.
+ ImplicitParamDecl AlgoVerArg(C, /*DC=*/nullptr, SourceLocation(),
+ /*Id=*/nullptr, C.ShortTy);
+ 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/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
index 4010b46a4cbd..ae25e94759e6 100644
--- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
+++ b/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/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 8370607db50f..0ebfd99363c1 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/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);
@@ -2127,16 +2127,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 +2157,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/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index 39e1cdfdbe2a..22269e42c7a0 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/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,38 @@ 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) &&
+ 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,6 +227,17 @@ static Address castValueFromUintptr(CodeGenFunction &CGF, QualType DstType,
return TmpAddr;
}
+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);
+}
+
llvm::Function *
CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
assert(
@@ -233,13 +277,8 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
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);
- }
+ getCanonicalParamType(getContext(), ArgType.getNonReferenceType());
}
Args.push_back(ImplicitParamDecl::Create(getContext(), nullptr,
FD->getLocation(), II, ArgType));
@@ -986,7 +1025,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
OriginalBaseLValue);
// Store the address of the original variable associated with the LHS
// implicit variable.
- PrivateScope.addPrivate(LHSVD, [this, OASELValueLB]() -> Address {
+ PrivateScope.addPrivate(LHSVD, [OASELValueLB]() -> Address {
return OASELValueLB.getAddress();
});
// Emit reduction copy.
@@ -1040,9 +1079,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
*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();
- });
+ PrivateScope.addPrivate(
+ LHSVD, [ASELValue]() -> Address { return ASELValue.getAddress(); });
// Emit reduction copy.
bool IsRegistered = PrivateScope.addPrivate(
OrigVD, [this, OrigVD, PrivateVD, BaseLValue, ASELValue,
@@ -1158,7 +1196,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
}
void CodeGenFunction::EmitOMPReductionClauseFinal(
- const OMPExecutableDirective &D) {
+ const OMPExecutableDirective &D, const OpenMPDirectiveKind ReductionKind) {
if (!HaveInsertPoint())
return;
llvm::SmallVector<const Expr *, 8> Privates;
@@ -1174,14 +1212,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});
}
}
@@ -1214,10 +1253,9 @@ 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);
+ 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,7 +1277,7 @@ static void emitCommonOMPParallelDirective(CodeGenFunction &CGF,
}
}
- OMPLexicalScope Scope(CGF, S);
+ OMPParallelScope Scope(CGF, S);
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getLocStart(), OutlinedFn,
@@ -1264,7 +1302,7 @@ 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);
emitPostUpdateForReductionClause(
@@ -1677,7 +1715,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; });
}
@@ -2003,15 +2041,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(
@@ -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 * {
@@ -2320,8 +2352,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 +2428,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 * {
@@ -2633,7 +2664,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
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, CS, &BodyGen, &LastprivateDstsOrigs](
CodeGenFunction &CGF, PrePostActionTy &Action) {
// Set proper addresses for generated private copies.
OMPPrivateScope Scope(CGF);
@@ -3250,7 +3281,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 +3308,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;
};
@@ -3404,41 +3435,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 +3467,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 +3545,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 +3558,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 +3824,47 @@ 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);
+ 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(
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 1a09830b52fd..7b0c8bf7d6e9 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/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());
@@ -380,8 +383,8 @@ void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD,
CGM.ConstructAttributeList(CalleePtr->getName(),
*CurFnInfo, MD, AttributeList,
CallingConv, /*AttrOnCallSite=*/true);
- llvm::AttributeSet Attrs =
- llvm::AttributeSet::get(getLLVMContext(), AttributeList);
+ llvm::AttributeList Attrs =
+ llvm::AttributeList::get(getLLVMContext(), AttributeList);
Call->setAttributes(Attrs);
Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
@@ -744,9 +747,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;
@@ -942,7 +946,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/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 4fbf9f22a98d..84248cc64719 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -36,7 +36,6 @@ add_clang_library(clangCodeGen
CGAtomic.cpp
CGBlocks.cpp
CGBuiltin.cpp
- CGCUDABuiltin.cpp
CGCUDANV.cpp
CGCUDARuntime.cpp
CGCXX.cpp
@@ -55,6 +54,7 @@ add_clang_library(clangCodeGen
CGExprComplex.cpp
CGExprConstant.cpp
CGExprScalar.cpp
+ CGGPUBuiltin.cpp
CGLoopInfo.cpp
CGObjC.cpp
CGObjCGNU.cpp
@@ -75,8 +75,10 @@ add_clang_library(clangCodeGen
CodeGenPGO.cpp
CodeGenTBAA.cpp
CodeGenTypes.cpp
+ ConstantInitBuilder.cpp
CoverageMappingGen.cpp
ItaniumCXXABI.cpp
+ MacroPPCallbacks.cpp
MicrosoftCXXABI.cpp
ModuleBuilder.cpp
ObjectFilePCHContainerOperations.cpp
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 5f74141d75b3..b864069dc645 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/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");
@@ -216,13 +249,9 @@ namespace clang {
Ctx.setDiagnosticHotnessRequested(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 +304,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 +327,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 +336,7 @@ namespace clang {
void OptimizationFailureHandler(
const llvm::DiagnosticInfoOptimizationFailure &D);
};
-
+
void BackendConsumer::anchor() {}
}
@@ -377,7 +405,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 +418,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 +505,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;
@@ -568,36 +596,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 +706,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 +770,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 +812,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 +827,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 +847,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,6 +886,62 @@ 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) {
@@ -855,35 +959,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/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index e142a21b1e74..6e6eb7d7f13c 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -45,15 +45,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;
}
@@ -149,6 +149,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
@@ -200,7 +202,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:
@@ -607,11 +610,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";
}
@@ -707,6 +705,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 +753,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 +776,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 +818,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").
@@ -851,8 +874,12 @@ 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
+ Fn->addFnAttr("counting-function", getTarget().getMCountName());
+ }
if (RetTy->isVoidType()) {
// Void type; nothing to return.
@@ -935,6 +962,16 @@ 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 (CXXThisValue) {
+ SanitizerSet SkippedChecks;
+ SkippedChecks.set(SanitizerKind::ObjectSize, true);
+ QualType ThisTy = MD->getThisType(getContext());
+ EmitTypeCheck(TCK_Load, Loc, CXXThisValue, ThisTy,
+ getContext().getTypeAlignInChars(ThisTy->getPointeeType()),
+ SkippedChecks);
+ }
}
// If any of the arguments have a variably modified type, make sure to
@@ -1076,8 +1113,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 +1933,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/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 586134023240..fa72019eb08b 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -115,6 +115,8 @@ 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, 0) \
SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \
SANITIZER_CHECK(NonnullReturn, nonnull_return, 0) \
SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \
@@ -212,6 +214,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 +307,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 +582,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 +595,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 +654,10 @@ public:
rescopeLabels();
}
+ bool hasLabels() const {
+ return !Labels.empty();
+ }
+
void rescopeLabels();
};
@@ -727,13 +765,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 +1158,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 +1377,16 @@ 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;
+ }
+
llvm::BasicBlock *TerminateLandingPad;
llvm::BasicBlock *TerminateHandler;
llvm::BasicBlock *TrapBB;
@@ -1553,6 +1606,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);
@@ -1710,6 +1765,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, SourceLocation EndLoc);
+
/// EmitStartEHSpec - Emit the start of the exception spec.
void EmitStartEHSpec(const Decl *D);
@@ -1928,7 +1986,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 +2077,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 +2291,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 +2304,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 +2464,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 +2532,13 @@ 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);
+ RValue EmitCoyieldExpr(const CoyieldExpr &E,
+ AggValueSlot aggSlot = AggValueSlot::ignored(),
+ bool ignoreResult = false);
RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID);
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
@@ -2627,7 +2703,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.
///
@@ -2704,13 +2782,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.
@@ -2843,6 +2924,13 @@ 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.
@@ -2883,7 +2971,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
@@ -3092,8 +3180,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 +3237,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);
@@ -3396,6 +3486,10 @@ 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);
+
/// \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 +3523,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 +3587,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 +3634,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,12 +3676,12 @@ 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);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 36005430ae4c..d48bff9c30a3 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/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,6 +41,7 @@
#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"
@@ -406,8 +406,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 +419,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.
@@ -833,7 +842,7 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
AttributeListType AttributeList;
ConstructAttributeList(F->getName(), Info, D, AttributeList, CallingConv,
false);
- F->setAttributes(llvm::AttributeSet::get(getLLVMContext(), AttributeList));
+ F->setAttributes(llvm::AttributeList::get(getLLVMContext(), AttributeList));
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
@@ -882,10 +891,10 @@ 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,
+ llvm::AttributeList::get(F->getContext(),
+ llvm::AttributeList::FunctionIndex, B));
return;
}
@@ -951,9 +960,9 @@ 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,
+ llvm::AttributeList::get(
+ F->getContext(), llvm::AttributeList::FunctionIndex, B));
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)
@@ -1029,7 +1038,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.
@@ -1107,7 +1115,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
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 +1124,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);
}
@@ -1482,6 +1490,30 @@ 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::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)
@@ -1693,6 +1725,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 +1768,7 @@ namespace {
}
};
+ // Make sure we're not referencing non-imported vars or functions.
struct DLLImportFunctionVisitor
: public RecursiveASTVisitor<DLLImportFunctionVisitor> {
bool SafeToInline = true;
@@ -1733,12 +1776,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 +1803,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 +1853,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,22 +1888,6 @@ 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());
- }
-}
-
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
const auto *D = cast<ValueDecl>(GD.getDecl());
@@ -1858,7 +1902,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 +1936,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 +2029,11 @@ 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,
+ llvm::AttributeList::get(
+ VMContext, llvm::AttributeList::FunctionIndex, B));
}
if (!DontDefer) {
@@ -2069,7 +2108,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 +2154,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 +2182,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);
@@ -2803,7 +2841,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 +2935,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 +2946,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 +2982,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 +3366,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:
@@ -3790,6 +3816,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))
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 36f6785fd1b9..d0b2dd717c8c 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/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"
@@ -546,6 +547,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(); }
@@ -906,14 +911,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);
@@ -1022,6 +1026,25 @@ public:
CGCalleeInfo CalleeInfo, AttributeListType &PAL,
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.
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
@@ -1103,6 +1126,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 +1205,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 +1219,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 +1250,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();
@@ -1266,6 +1293,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();
@@ -1304,6 +1335,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/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index c6c3fa41e628..6acedc033a6e 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -612,7 +612,7 @@ 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) {
@@ -626,12 +626,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);
@@ -737,7 +739,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 +748,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/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
index 4f229cde63b0..0026df570bce 100644
--- a/lib/CodeGen/CodeGenPGO.h
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -105,7 +105,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/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index adb40c8c0d47..dc24b2040f04 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -472,7 +472,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,7 +486,8 @@ 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);
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 2ce6591e4eb7..f0b97ebde1c2 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -303,11 +303,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/lib/CodeGen/ConstantBuilder.h b/lib/CodeGen/ConstantBuilder.h
deleted file mode 100644
index 40b34a9d61c8..000000000000
--- a/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/lib/CodeGen/ConstantInitBuilder.cpp b/lib/CodeGen/ConstantInitBuilder.cpp
new file mode 100644
index 000000000000..7f8d80985032
--- /dev/null
+++ b/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/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
index 5bc9e5011aa8..a1023473bdd3 100644
--- a/lib/CodeGen/CoverageMappingGen.cpp
+++ b/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/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h
index 243583038558..c7bdeac58a1a 100644
--- a/lib/CodeGen/EHScopeStack.h
+++ b/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/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index f7a8dd66c527..dac2d15fa406 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/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"
@@ -207,8 +207,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 +226,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,
@@ -1134,8 +1134,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 +1353,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 +1362,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) {
@@ -1429,11 +1432,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 +1444,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,
@@ -1907,10 +1910,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 +1922,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 +1934,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 +2021,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 +2168,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),
@@ -2634,7 +2643,6 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
return false;
@@ -2814,7 +2822,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");
@@ -3044,7 +3053,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");
@@ -3534,8 +3544,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 +3930,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/lib/CodeGen/MacroPPCallbacks.cpp b/lib/CodeGen/MacroPPCallbacks.cpp
new file mode 100644
index 000000000000..acea5c1143cf
--- /dev/null
+++ b/lib/CodeGen/MacroPPCallbacks.cpp
@@ -0,0 +1,207 @@
+//===--- 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.arg_empty()) {
+ MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_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) {
+ IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
+ SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
+ Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
+ llvm::dwarf::DW_MACINFO_undef, location,
+ Id->getName(), "");
+}
diff --git a/lib/CodeGen/MacroPPCallbacks.h b/lib/CodeGen/MacroPPCallbacks.h
new file mode 100644
index 000000000000..06217f9c5883
--- /dev/null
+++ b/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) override;
+};
+
+} // end namespace clang
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 38df455011e3..4cacf494e694 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/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,
@@ -1261,17 +1261,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 +1281,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) {
@@ -1493,14 +1500,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 +1518,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 +1561,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 +2210,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 +2307,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 +2319,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 +2331,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);
}
@@ -3713,7 +3719,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 =
@@ -3918,16 +3924,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/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index f925c2549175..89090c8b6a1b 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -92,6 +92,10 @@ namespace {
return M.get();
}
+ CGDebugInfo *getCGDebugInfo() {
+ return Builder->getModuleDebugInfo();
+ }
+
llvm::Module *ReleaseModule() {
return M.release();
}
@@ -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/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index 754f9968b67f..37ecc05aa1ee 100644
--- a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -171,7 +171,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 +242,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/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index d2fc3888ef29..94c3880ea26e 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -1197,6 +1197,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 +1240,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 +1251,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.
@@ -1885,10 +1901,10 @@ 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,
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex, B));
}
if (FD->hasAttr<AnyX86InterruptAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
@@ -4819,7 +4835,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 {
@@ -4901,7 +4917,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.
@@ -4951,7 +4967,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.
@@ -5433,10 +5449,10 @@ 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,
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex, B));
}
};
@@ -6884,6 +6900,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.
@@ -7261,9 +7302,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");
@@ -8386,6 +8432,9 @@ 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;
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 3ebd1c4f891e..43d6aa8f99b8 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -11,21 +11,54 @@ endif()
add_clang_library(clangDriver
Action.cpp
Compilation.cpp
- CrossWindowsToolChain.cpp
Distro.cpp
Driver.cpp
DriverOptions.cpp
Job.cpp
- MinGWToolChain.cpp
Multilib.cpp
- MSVCToolChain.cpp
Phases.cpp
SanitizerArgs.cpp
Tool.cpp
ToolChain.cpp
- ToolChains.cpp
- Tools.cpp
+ ToolChains/Arch/AArch64.cpp
+ ToolChains/Arch/ARM.cpp
+ ToolChains/Arch/Mips.cpp
+ ToolChains/Arch/PPC.cpp
+ ToolChains/Arch/Sparc.cpp
+ ToolChains/Arch/SystemZ.cpp
+ ToolChains/Arch/X86.cpp
+ ToolChains/AMDGPU.cpp
+ ToolChains/AVR.cpp
+ ToolChains/Bitrig.cpp
+ ToolChains/Clang.cpp
+ ToolChains/CloudABI.cpp
+ ToolChains/CommonArgs.cpp
+ ToolChains/Contiki.cpp
+ ToolChains/CrossWindows.cpp
+ ToolChains/Cuda.cpp
+ ToolChains/Darwin.cpp
+ ToolChains/DragonFly.cpp
+ ToolChains/FreeBSD.cpp
+ ToolChains/Fuchsia.cpp
+ ToolChains/Gnu.cpp
+ ToolChains/Haiku.cpp
+ ToolChains/Hexagon.cpp
+ ToolChains/Linux.cpp
+ ToolChains/MipsLinux.cpp
+ ToolChains/MinGW.cpp
+ ToolChains/Minix.cpp
+ ToolChains/MSVC.cpp
+ ToolChains/Myriad.cpp
+ ToolChains/NaCl.cpp
+ ToolChains/NetBSD.cpp
+ ToolChains/OpenBSD.cpp
+ ToolChains/PS4CPU.cpp
+ ToolChains/Solaris.cpp
+ ToolChains/TCE.cpp
+ ToolChains/WebAssembly.cpp
+ ToolChains/XCore.cpp
Types.cpp
+ XRayArgs.cpp
DEPENDS
ClangDriverOptions
diff --git a/lib/Driver/CrossWindowsToolChain.cpp b/lib/Driver/CrossWindowsToolChain.cpp
deleted file mode 100644
index 28036ea51cff..000000000000
--- a/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/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 15f830d029eb..f36deff5d734 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -9,7 +9,36 @@
#include "clang/Driver/Driver.h"
#include "InputInfo.h"
-#include "ToolChains.h"
+#include "ToolChains/AMDGPU.h"
+#include "ToolChains/AVR.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/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 +91,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 +108,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);
@@ -214,9 +238,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 +311,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 +503,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);
}
//
@@ -596,6 +620,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()) {
@@ -1145,6 +1172,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;
@@ -1462,16 +1494,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 +1592,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 +1620,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 +2390,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 +2540,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 =
@@ -3186,7 +3229,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 +3701,130 @@ 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::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 (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/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index 8d5332b5cc24..6a7410901d25 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -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/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 9fd8808af302..7a4d055159ec 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -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/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp
deleted file mode 100644
index 17fd6ac6f714..000000000000
--- a/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/lib/Driver/MinGWToolChain.cpp b/lib/Driver/MinGWToolChain.cpp
deleted file mode 100644
index e971869fb569..000000000000
--- a/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/lib/Driver/Multilib.cpp b/lib/Driver/Multilib.cpp
index a88edf7f04e3..43b62f7b3612 100644
--- a/lib/Driver/Multilib.cpp
+++ b/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"
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index f4f6dad9f287..b05596a99f6e 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/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 | Memory | Leak | Undefined | Integer | Nullability | DataFlow,
+ 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,
};
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 6adc0386ee7b..4f82503276f4 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/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;
@@ -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) ||
@@ -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/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
deleted file mode 100644
index 9bc9ae4f6a52..000000000000
--- a/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/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
deleted file mode 100644
index 3240357ba6b1..000000000000
--- a/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/lib/Driver/ToolChains/AMDGPU.cpp b/lib/Driver/ToolChains/AMDGPU.cpp
new file mode 100644
index 000000000000..63e1749e0088
--- /dev/null
+++ b/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/lib/Driver/ToolChains/AMDGPU.h b/lib/Driver/ToolChains/AMDGPU.h
new file mode 100644
index 000000000000..9af1e96489eb
--- /dev/null
+++ b/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/lib/Driver/ToolChains/AVR.cpp b/lib/Driver/ToolChains/AVR.cpp
new file mode 100644
index 000000000000..877009af8a30
--- /dev/null
+++ b/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/lib/Driver/ToolChains/AVR.h b/lib/Driver/ToolChains/AVR.h
new file mode 100644
index 000000000000..a7479a7f5652
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/AArch64.cpp b/lib/Driver/ToolChains/Arch/AArch64.cpp
new file mode 100644
index 000000000000..554d051fb155
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/AArch64.h b/lib/Driver/ToolChains/Arch/AArch64.h
new file mode 100644
index 000000000000..62e419cc19f7
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp
new file mode 100644
index 000000000000..4eac97620114
--- /dev/null
+++ b/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -0,0 +1,547 @@
+//===--- 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::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);
+ }
+
+ 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");
+
+ 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/lib/Driver/ToolChains/Arch/ARM.h b/lib/Driver/ToolChains/Arch/ARM.h
new file mode 100644
index 000000000000..52afaab762d0
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/Mips.cpp b/lib/Driver/ToolChains/Arch/Mips.cpp
new file mode 100644
index 000000000000..cd791af83220
--- /dev/null
+++ b/lib/Driver/ToolChains/Arch/Mips.cpp
@@ -0,0 +1,403 @@
+//===--- 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(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");
+}
+
+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/lib/Driver/ToolChains/Arch/Mips.h b/lib/Driver/ToolChains/Arch/Mips.h
new file mode 100644
index 000000000000..0b788660948c
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/PPC.cpp b/lib/Driver/ToolChains/Arch/PPC.cpp
new file mode 100644
index 000000000000..541323127f9a
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/PPC.h b/lib/Driver/ToolChains/Arch/PPC.h
new file mode 100644
index 000000000000..892eb2c34158
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/Sparc.cpp b/lib/Driver/ToolChains/Arch/Sparc.cpp
new file mode 100644
index 000000000000..594ec9986d8e
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/Sparc.h b/lib/Driver/ToolChains/Arch/Sparc.h
new file mode 100644
index 000000000000..082b2808a946
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/SystemZ.cpp b/lib/Driver/ToolChains/Arch/SystemZ.cpp
new file mode 100644
index 000000000000..6ee724d00802
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/SystemZ.h b/lib/Driver/ToolChains/Arch/SystemZ.h
new file mode 100644
index 000000000000..521f8c2aad02
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/X86.cpp b/lib/Driver/ToolChains/Arch/X86.cpp
new file mode 100644
index 000000000000..a85a7f1f6371
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Arch/X86.h b/lib/Driver/ToolChains/Arch/X86.h
new file mode 100644
index 000000000000..20bf27a2b6bc
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Bitrig.cpp b/lib/Driver/ToolChains/Bitrig.cpp
new file mode 100644
index 000000000000..d8f541dfbaf1
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Bitrig.h b/lib/Driver/ToolChains/Bitrig.h
new file mode 100644
index 000000000000..6edb2e8c7e8c
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp
new file mode 100644
index 000000000000..f8eeeb4eef69
--- /dev/null
+++ b/lib/Driver/ToolChains/Clang.cpp
@@ -0,0 +1,5160 @@
+//===--- 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/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>());
+
+ //
+ // 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
+ CmdArgs.push_back(types::getTypeName(Input.getType()));
+}
+
+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) &&
+ !ProfileGenerateArg)
+ D.Diag(clang::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));
+ }
+ }
+ }
+}
+
+/// \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 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));
+ }
+
+ 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 if (Triple.isOSBinFormatMachO()) {
+ if (arm::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 if (Triple.getOS() == llvm::Triple::OpenBSD)
+ ABIName = "aapcs-linux";
+ 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");
+}
+
+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;
+
+ // 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);
+ }
+}
+
+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);
+
+ // The Darwin linker currently uses the legacy LTO API, which does not
+ // support LTO unit features (CFI, whole program vtable opt) under
+ // ThinLTO.
+ if (!getToolChain().getTriple().isOSDarwin() ||
+ 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_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() ||
+ 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();
+ }
+ // 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() && 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);
+
+ // -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");
+ }
+
+ 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);
+
+ // 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();
+ }
+
+ 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_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;
+ }
+
+ // -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.
+ // -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 && 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);
+}
+
+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");
+ }
+
+ 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();
+}
+
+
+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();
+
+ // 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));
+}
+
+// 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/lib/Driver/ToolChains/Clang.h b/lib/Driver/ToolChains/Clang.h
new file mode 100644
index 000000000000..d53c3b4413c8
--- /dev/null
+++ b/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/lib/Driver/ToolChains/CloudABI.cpp b/lib/Driver/ToolChains/CloudABI.cpp
new file mode 100644
index 000000000000..0f6c712c5d28
--- /dev/null
+++ b/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/lib/Driver/ToolChains/CloudABI.h b/lib/Driver/ToolChains/CloudABI.h
new file mode 100644
index 000000000000..a284eb3dc0a4
--- /dev/null
+++ b/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/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp
new file mode 100644
index 000000000000..e5f4a3b8d605
--- /dev/null
+++ b/lib/Driver/ToolChains/CommonArgs.cpp
@@ -0,0 +1,973 @@
+//===--- 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 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::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()));
+ }
+}
+
+void tools::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;
+ }
+
+ addArchSpecificRPath(TC, Args, CmdArgs);
+}
+
+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::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");
+}
+
+// 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);
+ 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/lib/Driver/ToolChains/CommonArgs.h b/lib/Driver/ToolChains/CommonArgs.h
new file mode 100644
index 000000000000..f5747aa85f22
--- /dev/null
+++ b/lib/Driver/ToolChains/CommonArgs.h
@@ -0,0 +1,96 @@
+//===--- 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);
+void addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
+ const llvm::opt::ArgList &Args);
+
+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/lib/Driver/ToolChains/Contiki.cpp b/lib/Driver/ToolChains/Contiki.cpp
new file mode 100644
index 000000000000..7f74bfcb4b01
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Contiki.h b/lib/Driver/ToolChains/Contiki.h
new file mode 100644
index 000000000000..f6e15073887b
--- /dev/null
+++ b/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/lib/Driver/ToolChains/CrossWindows.cpp b/lib/Driver/ToolChains/CrossWindows.cpp
new file mode 100644
index 000000000000..b030c636adab
--- /dev/null
+++ b/lib/Driver/ToolChains/CrossWindows.cpp
@@ -0,0 +1,309 @@
+//===--- 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 (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/lib/Driver/ToolChains/CrossWindows.h b/lib/Driver/ToolChains/CrossWindows.h
new file mode 100644
index 000000000000..5375a6324a3f
--- /dev/null
+++ b/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 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/lib/Driver/ToolChains/Cuda.cpp b/lib/Driver/ToolChains/Cuda.cpp
new file mode 100644
index 000000000000..42bf164f1b3f
--- /dev/null
+++ b/lib/Driver/ToolChains/Cuda.cpp
@@ -0,0 +1,488 @@
+//===--- 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) 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);
+}
diff --git a/lib/Driver/ToolChains/Cuda.h b/lib/Driver/ToolChains/Cuda.h
new file mode 100644
index 000000000000..acdb4c4efd6d
--- /dev/null
+++ b/lib/Driver/ToolChains/Cuda.h
@@ -0,0 +1,177 @@
+//===--- 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) 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/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp
new file mode 100644
index 000000000000..009a12da3015
--- /dev/null
+++ b/lib/Driver/ToolChains/Darwin.cpp
@@ -0,0 +1,1910 @@
+//===--- 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));
+ }
+}
+
+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.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,
+ 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);
+
+ // 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 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(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);
+}
+
+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 {
+ 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);
+}
diff --git a/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h
new file mode 100644
index 000000000000..984f8ef0c41f
--- /dev/null
+++ b/lib/Driver/ToolChains/Darwin.h
@@ -0,0 +1,488 @@
+//===--- 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 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;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H
diff --git a/lib/Driver/ToolChains/DragonFly.cpp b/lib/Driver/ToolChains/DragonFly.cpp
new file mode 100644
index 000000000000..bd2c7fc6c4bd
--- /dev/null
+++ b/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/lib/Driver/ToolChains/DragonFly.h b/lib/Driver/ToolChains/DragonFly.h
new file mode 100644
index 000000000000..9a06fbd0d3c2
--- /dev/null
+++ b/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/lib/Driver/ToolChains/FreeBSD.cpp b/lib/Driver/ToolChains/FreeBSD.cpp
new file mode 100644
index 000000000000..c6626e922eef
--- /dev/null
+++ b/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/lib/Driver/ToolChains/FreeBSD.h b/lib/Driver/ToolChains/FreeBSD.h
new file mode 100644
index 000000000000..25e9df72bc80
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Fuchsia.cpp b/lib/Driver/ToolChains/Fuchsia.cpp
new file mode 100644
index 000000000000..b8757cf4aa73
--- /dev/null
+++ b/lib/Driver/ToolChains/Fuchsia.cpp
@@ -0,0 +1,229 @@
+//===--- 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");
+ }
+
+ 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.
+
+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(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) 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");
+}
+
+SanitizerMask Fuchsia::getSupportedSanitizers() const {
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::SafeStack;
+ return Res;
+}
diff --git a/lib/Driver/ToolChains/Fuchsia.h b/lib/Driver/ToolChains/Fuchsia.h
new file mode 100644
index 000000000000..1a8c9903fe4d
--- /dev/null
+++ b/lib/Driver/ToolChains/Fuchsia.h
@@ -0,0 +1,79 @@
+//===--- 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 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;
+ }
+
+ 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) 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;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H
diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp
new file mode 100644
index 000000000000..549e24cbd2b3
--- /dev/null
+++ b/lib/Driver/ToolChains/Gnu.cpp
@@ -0,0 +1,2426 @@
+//===--- 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";
+ 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;
+}
+
+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);
+
+ 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");
+
+ addArchSpecificRPath(ToolChain, Args, CmdArgs);
+ }
+
+ 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 {
+ 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(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::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"));
+}
+
+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("+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;
+}
+
+/// 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;
+}
+
+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"};
+ 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 {
+ 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 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::anchor() {}
+
+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");
+}
diff --git a/lib/Driver/ToolChains/Gnu.h b/lib/Driver/ToolChains/Gnu.h
new file mode 100644
index 000000000000..1dc1ad49e305
--- /dev/null
+++ b/lib/Driver/ToolChains/Gnu.h
@@ -0,0 +1,351 @@
+//===--- 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 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) const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H
diff --git a/lib/Driver/ToolChains/Haiku.cpp b/lib/Driver/ToolChains/Haiku.cpp
new file mode 100644
index 000000000000..284d269a0c1b
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Haiku.h b/lib/Driver/ToolChains/Haiku.h
new file mode 100644
index 000000000000..8b5b48e59023
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Hexagon.cpp b/lib/Driver/ToolChains/Hexagon.cpp
new file mode 100644
index 000000000000..c143b7f89868
--- /dev/null
+++ b/lib/Driver/ToolChains/Hexagon.cpp
@@ -0,0 +1,457 @@
+//===--- 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);
+}
+
+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/lib/Driver/ToolChains/Hexagon.h b/lib/Driver/ToolChains/Hexagon.h
new file mode 100644
index 000000000000..fb50ba3c72c3
--- /dev/null
+++ b/lib/Driver/ToolChains/Hexagon.h
@@ -0,0 +1,99 @@
+//===--- 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;
+
+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);
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H
diff --git a/lib/Driver/ToolChains/Lanai.h b/lib/Driver/ToolChains/Lanai.h
new file mode 100644
index 000000000000..4ce658dc7775
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp
new file mode 100644
index 000000000000..3ffb2f6e03e5
--- /dev/null
+++ b/lib/Driver/ToolChains/Linux.cpp
@@ -0,0 +1,901 @@
+//===--- 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);
+}
+
+/// \brief Parse a GCCVersion object out of a string of text.
+///
+/// This is the primary means of forming GCCVersion objects.
+/*static*/
+Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
+ const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
+ std::pair<StringRef, StringRef> First = VersionText.split('.');
+ std::pair<StringRef, StringRef> Second = First.second.split('.');
+
+ GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
+ if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
+ return BadVersion;
+ GoodVersion.MajorStr = First.first.str();
+ if (First.second.empty())
+ return GoodVersion;
+ if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
+ return BadVersion;
+ GoodVersion.MinorStr = Second.first.str();
+
+ // First look for a number prefix and parse that if present. Otherwise just
+ // stash the entire patch string in the suffix, and leave the number
+ // unspecified. This covers versions strings such as:
+ // 5 (handled above)
+ // 4.4
+ // 4.4.0
+ // 4.4.x
+ // 4.4.2-rc4
+ // 4.4.x-patched
+ // And retains any patch number it finds.
+ StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
+ if (!PatchText.empty()) {
+ if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
+ // Try to parse the number and any suffix.
+ if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
+ GoodVersion.Patch < 0)
+ return BadVersion;
+ GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
+ }
+ }
+
+ return GoodVersion;
+}
+
+bool Linux::HasNativeLLVMSupport() const { return true; }
+
+Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); }
+
+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 ||
+ llvm::Triple::thumb || llvm::Triple::armeb ||
+ llvm::Triple::thumbeb;
+ 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 || 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/lib/Driver/ToolChains/Linux.h b/lib/Driver/ToolChains/Linux.h
new file mode 100644
index 000000000000..9778c1832ccc
--- /dev/null
+++ b/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/lib/Driver/ToolChains/MSVC.cpp b/lib/Driver/ToolChains/MSVC.cpp
new file mode 100644
index 000000000000..a09304814ca6
--- /dev/null
+++ b/lib/Driver/ToolChains/MSVC.cpp
@@ -0,0 +1,1421 @@
+//===--- 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,
+ bool &IsVS2017OrNewer) {
+ // 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);
+ IsVS2017OrNewer = true;
+ 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);
+ IsVS2017OrNewer = false;
+ 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.
+ if (llvm::sys::path::filename(PathEntry) == "bin") {
+ llvm::StringRef ParentPath = llvm::sys::path::parent_path(PathEntry);
+ if (llvm::sys::path::filename(ParentPath) == "VC") {
+ Path = ParentPath;
+ IsVS2017OrNewer = false;
+ 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;
+ IsVS2017OrNewer = true;
+ 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,
+ bool &IsVS2017OrNewer) {
+#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();
+ IsVS2017OrNewer = true;
+ 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,
+ bool &IsVS2017OrNewer) {
+ 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();
+ IsVS2017OrNewer = false;
+ 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
+ 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 = Linker;
+ llvm::sys::path::replace_extension(linkPath, "exe");
+ linkPath = TC.GetProgramPath(linkPath.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, IsVS2017OrNewer) ||
+ findVCToolChainViaSetupConfig(VCToolChainPath, IsVS2017OrNewer) ||
+ findVCToolChainViaRegistry(VCToolChainPath, IsVS2017OrNewer);
+}
+
+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 {
+ // 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 "";
+ }
+}
+
+// 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 {
+ llvm::SmallString<256> Path(VCToolChainPath);
+ switch (Type) {
+ case SubDirectoryType::Bin:
+ if (IsVS2017OrNewer) {
+ bool HostIsX64 =
+ llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
+ llvm::sys::path::append(Path, "bin", (HostIsX64 ? "HostX64" : "HostX86"),
+ llvmArchToWindowsSDKArch(TargetArch));
+
+ } else {
+ llvm::sys::path::append(Path, "bin", llvmArchToLegacyVCArch(TargetArch));
+ }
+ break;
+ case SubDirectoryType::Include:
+ llvm::sys::path::append(Path, "include");
+ break;
+ case SubDirectoryType::Lib:
+ llvm::sys::path::append(
+ Path, "lib", IsVS2017OrNewer ? llvmArchToWindowsSDKArch(TargetArch)
+ : llvmArchToLegacyVCArch(TargetArch));
+ 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/lib/Driver/ToolChains/MSVC.h b/lib/Driver/ToolChains/MSVC.h
new file mode 100644
index 000000000000..055830c52e0d
--- /dev/null
+++ b/lib/Driver/ToolChains/MSVC.h
@@ -0,0 +1,141 @@
+//===--- 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 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());
+ }
+
+ bool getIsVS2017OrNewer() const { return IsVS2017OrNewer; }
+
+ 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;
+ bool IsVS2017OrNewer = false;
+ CudaInstallationDetector CudaInstallation;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H
diff --git a/lib/Driver/ToolChains/MSVCSetupApi.h b/lib/Driver/ToolChains/MSVCSetupApi.h
new file mode 100644
index 000000000000..a890b85fd5e9
--- /dev/null
+++ b/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/lib/Driver/ToolChains/MinGW.cpp b/lib/Driver/ToolChains/MinGW.cpp
new file mode 100644
index 000000000000..ca5bf06f7e7d
--- /dev/null
+++ b/lib/Driver/ToolChains/MinGW.cpp
@@ -0,0 +1,471 @@
+//===--- 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;
+ }
+ }
+ }
+}
+
+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());
+
+// 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 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 {
+ 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/lib/Driver/ToolChains/MinGW.h b/lib/Driver/ToolChains/MinGW.h
new file mode 100644
index 000000000000..9d2468ffa234
--- /dev/null
+++ b/lib/Driver/ToolChains/MinGW.h
@@ -0,0 +1,102 @@
+//===--- 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 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();
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H
diff --git a/lib/Driver/ToolChains/Minix.cpp b/lib/Driver/ToolChains/Minix.cpp
new file mode 100644
index 000000000000..2e8939c40150
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Minix.h b/lib/Driver/ToolChains/Minix.h
new file mode 100644
index 000000000000..6fd71850ad06
--- /dev/null
+++ b/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/lib/Driver/ToolChains/MipsLinux.cpp b/lib/Driver/ToolChains/MipsLinux.cpp
new file mode 100644
index 000000000000..709c396a64b7
--- /dev/null
+++ b/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 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();
+}
diff --git a/lib/Driver/ToolChains/MipsLinux.h b/lib/Driver/ToolChains/MipsLinux.h
new file mode 100644
index 000000000000..fa82efbbfc8f
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Myriad.cpp b/lib/Driver/ToolChains/Myriad.cpp
new file mode 100644
index 000000000000..2935755c12be
--- /dev/null
+++ b/lib/Driver/ToolChains/Myriad.cpp
@@ -0,0 +1,286 @@
+//===--- 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, 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));
+}
+
+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";
+ 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/lib/Driver/ToolChains/Myriad.h b/lib/Driver/ToolChains/Myriad.h
new file mode 100644
index 000000000000..4c213c726219
--- /dev/null
+++ b/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/lib/Driver/ToolChains/NaCl.cpp b/lib/Driver/ToolChains/NaCl.cpp
new file mode 100644
index 000000000000..5eb5c74f1310
--- /dev/null
+++ b/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/lib/Driver/ToolChains/NaCl.h b/lib/Driver/ToolChains/NaCl.h
new file mode 100644
index 000000000000..31af3a53ad3c
--- /dev/null
+++ b/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/lib/Driver/ToolChains/NetBSD.cpp b/lib/Driver/ToolChains/NetBSD.cpp
new file mode 100644
index 000000000000..d7d3ad61df42
--- /dev/null
+++ b/lib/Driver/ToolChains/NetBSD.cpp
@@ -0,0 +1,412 @@
+//===--- 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 "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);
+
+ 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));
+}
+
+/// 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);
+}
diff --git a/lib/Driver/ToolChains/NetBSD.h b/lib/Driver/ToolChains/NetBSD.h
new file mode 100644
index 000000000000..d53aa6867872
--- /dev/null
+++ b/lib/Driver/ToolChains/NetBSD.h
@@ -0,0 +1,79 @@
+//===--- 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 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_NETBSD_H
diff --git a/lib/Driver/ToolChains/OpenBSD.cpp b/lib/Driver/ToolChains/OpenBSD.cpp
new file mode 100644
index 000000000000..c5f266ec8fdc
--- /dev/null
+++ b/lib/Driver/ToolChains/OpenBSD.cpp
@@ -0,0 +1,234 @@
+//===--- 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_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/lib/Driver/ToolChains/OpenBSD.h b/lib/Driver/ToolChains/OpenBSD.h
new file mode 100644
index 000000000000..1cc0ca71984a
--- /dev/null
+++ b/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/lib/Driver/ToolChains/PS4CPU.cpp b/lib/Driver/ToolChains/PS4CPU.cpp
new file mode 100644
index 000000000000..c1b8c3d66077
--- /dev/null
+++ b/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/lib/Driver/ToolChains/PS4CPU.h b/lib/Driver/ToolChains/PS4CPU.h
new file mode 100644
index 000000000000..e507edbad4d5
--- /dev/null
+++ b/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/lib/Driver/ToolChains/Solaris.cpp b/lib/Driver/ToolChains/Solaris.cpp
new file mode 100644
index 000000000000..78797c49d7b6
--- /dev/null
+++ b/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_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());
+ }
+}
diff --git a/lib/Driver/ToolChains/Solaris.h b/lib/Driver/ToolChains/Solaris.h
new file mode 100644
index 000000000000..edb44373b31d
--- /dev/null
+++ b/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_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;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H
diff --git a/lib/Driver/ToolChains/TCE.cpp b/lib/Driver/ToolChains/TCE.cpp
new file mode 100644
index 000000000000..ae8a1c806485
--- /dev/null
+++ b/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/lib/Driver/ToolChains/TCE.h b/lib/Driver/ToolChains/TCE.h
new file mode 100644
index 000000000000..4644f4eedb0e
--- /dev/null
+++ b/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/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp
new file mode 100644
index 000000000000..123a1516f1e7
--- /dev/null
+++ b/lib/Driver/ToolChains/WebAssembly.cpp
@@ -0,0 +1,163 @@
+//===--- 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("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));
+}
+
+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(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/lib/Driver/ToolChains/WebAssembly.h b/lib/Driver/ToolChains/WebAssembly.h
new file mode 100644
index 000000000000..ca42fc651a6d
--- /dev/null
+++ b/lib/Driver/ToolChains/WebAssembly.h
@@ -0,0 +1,77 @@
+//===--- 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) 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/lib/Driver/ToolChains/XCore.cpp b/lib/Driver/ToolChains/XCore.cpp
new file mode 100644
index 000000000000..c3ae9582124f
--- /dev/null
+++ b/lib/Driver/ToolChains/XCore.cpp
@@ -0,0 +1,149 @@
+//===--- 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) 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/lib/Driver/ToolChains/XCore.h b/lib/Driver/ToolChains/XCore.h
new file mode 100644
index 000000000000..4084b1cdec13
--- /dev/null
+++ b/lib/Driver/ToolChains/XCore.h
@@ -0,0 +1,82 @@
+//===--- 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) 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/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
deleted file mode 100644
index 3c3d453ff7d1..000000000000
--- a/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/lib/Driver/Tools.h b/lib/Driver/Tools.h
deleted file mode 100644
index 9d5b892d424c..000000000000
--- a/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/lib/Driver/XRayArgs.cpp b/lib/Driver/XRayArgs.cpp
new file mode 100644
index 000000000000..8d68a8432d39
--- /dev/null
+++ b/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/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index 6363f895f95b..c97486e4e4a7 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/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,21 @@ 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,
@@ -132,37 +147,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 +210,149 @@ 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.
+ static const SmallVector<StringRef, 4> kSpecialMeaningPrefixes = {
+ "@", "TODO", "FIXME", "XXX"};
+ bool hasSpecialMeaningPrefix = false;
+ for (StringRef Prefix : kSpecialMeaningPrefixes) {
+ if (Content.startswith(Prefix)) {
+ hasSpecialMeaningPrefix = true;
+ break;
+ }
+ }
+ // 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 +364,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 +447,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 +615,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 +652,248 @@ 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] = "//! ";
+ }
+
+ 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/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index eb1f9fda3071..e642a538e21c 100644
--- a/lib/Format/BreakableToken.h
+++ b/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/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
index c977c2d3c5fa..0c7511c1bb07 100644
--- a/lib/Format/CMakeLists.txt
+++ b/lib/Format/CMakeLists.txt
@@ -3,11 +3,11 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangFormat
AffectedRangeManager.cpp
BreakableToken.cpp
- Comments.cpp
ContinuationIndenter.cpp
Format.cpp
FormatToken.cpp
FormatTokenLexer.cpp
+ NamespaceEndCommentsFixer.cpp
SortJavaScriptImports.cpp
TokenAnalyzer.cpp
TokenAnnotator.cpp
diff --git a/lib/Format/Comments.cpp b/lib/Format/Comments.cpp
deleted file mode 100644
index 1b27f5b30a60..000000000000
--- a/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/lib/Format/Comments.h b/lib/Format/Comments.h
deleted file mode 100644
index 59f0596361a5..000000000000
--- a/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/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 6bb6fb306035..73ae10a29f8f 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/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 {
@@ -57,8 +57,10 @@ static bool startsNextParameter(const FormatToken &Current,
Style.BreakConstructorInitializersBeforeComma)
return true;
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
- (Previous.isNot(TT_CtorInitializerComma) ||
- !Style.BreakConstructorInitializersBeforeComma);
+ ((Previous.isNot(TT_CtorInitializerComma) ||
+ !Style.BreakConstructorInitializersBeforeComma) &&
+ (Previous.isNot(TT_InheritanceComma) ||
+ !Style.BreakBeforeInheritanceComma));
}
ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
@@ -80,7 +82,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;
@@ -135,6 +137,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 +158,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
@@ -191,6 +199,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 +275,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 +349,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 +390,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 +407,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,6 +415,31 @@ 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;
@@ -540,9 +587,8 @@ 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);
+ Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column,
+ State.Line->InPPDirective);
}
if (!Current.isTrailingComment())
@@ -559,9 +605,7 @@ 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)
@@ -580,7 +624,9 @@ 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) ||
+ (PreviousNonComment->is(TT_TemplateString) &&
+ PreviousNonComment->opensScope())))
State.Stack.back().BreakBeforeClosingBrace = true;
if (State.Stack.back().AvoidBinPacking) {
@@ -628,14 +674,16 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
return State.Stack[State.Stack.size() - 2].LastSpace;
return State.FirstIndent;
}
+ 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 +744,11 @@ 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 (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 +765,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 +775,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)
@@ -765,9 +818,14 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
State.Stack.back().AvoidBinPacking = true;
State.Stack.back().BreakBeforeParameter = false;
}
+ 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 +853,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 +915,9 @@ 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;
// Indent from 'LastSpace' unless these are fake parentheses encapsulating
// a builder type call after 'return' or, if the alignment after opening
@@ -862,24 +932,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,7 +983,6 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
}
unsigned NewIndent;
- unsigned NewIndentLevel = State.Stack.back().IndentLevel;
unsigned LastSpace = State.Stack.back().LastSpace;
bool AvoidBinPacking;
bool BreakBeforeParameter = false;
@@ -941,7 +992,6 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
if (Current.opensBlockOrBlockTypeList(Style)) {
NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth;
NewIndent = std::min(State.Column + 2, NewIndent);
- ++NewIndentLevel;
} else {
NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
}
@@ -966,12 +1016,23 @@ 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;
+ }
+
AvoidBinPacking =
(State.Line->MustBeDeclaration && !Style.BinPackParameters) ||
(!State.Line->MustBeDeclaration && !Style.BinPackArguments) ||
@@ -1003,17 +1064,15 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
// 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 +1086,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 +1106,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 +1175,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 +1221,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 +1253,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 +1287,7 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
}
TailOffset += Split.first + Split.second;
RemainingTokenColumns = NewRemainingTokenColumns;
+ ReflowInProgress = true;
BreakInserted = true;
}
}
@@ -1233,6 +1308,9 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
State.Stack.back().LastSpace = StartColumn;
}
+
+ Token->updateNextToken(State);
+
return Penalty;
}
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index 21ad653c4fa4..9a06aa6f6267 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/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/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 389761d48249..0e2da71343d5 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -17,6 +17,7 @@
#include "AffectedRangeManager.h"
#include "ContinuationIndenter.h"
#include "FormatTokenLexer.h"
+#include "NamespaceEndCommentsFixer.h"
#include "SortJavaScriptImports.h"
#include "TokenAnalyzer.h"
#include "TokenAnnotator.h"
@@ -297,6 +298,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
+ IO.mapOptional("BreakBeforeInheritanceComma",
+ Style.BreakBeforeInheritanceComma);
IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
IO.mapOptional("ConstructorInitializerIndentWidth",
@@ -307,6 +310,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);
@@ -421,6 +425,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";
}
@@ -514,6 +523,7 @@ FormatStyle getLLVMStyle() {
false, false, false, false, false};
LLVMStyle.BreakAfterJavaFieldAnnotations = false;
LLVMStyle.BreakConstructorInitializersBeforeComma = false;
+ LLVMStyle.BreakBeforeInheritanceComma = false;
LLVMStyle.BreakStringLiterals = true;
LLVMStyle.ColumnLimit = 80;
LLVMStyle.CommentPragmas = "^ IWYU pragma:";
@@ -523,6 +533,7 @@ FormatStyle getLLVMStyle() {
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");
@@ -546,7 +557,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;
@@ -614,8 +624,9 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
GoogleStyle.BreakBeforeTernaryOperators = false;
- GoogleStyle.CommentPragmas =
- "(taze:|@(export|requirecss|return|returns|see|visibility)) ";
+ // taze:, @tag followed by { for a lot of JSDoc tags, and @see, which is
+ // commonly followed by overlong URLs.
+ GoogleStyle.CommentPragmas = "(taze:|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
GoogleStyle.SpacesInContainerLiterals = false;
@@ -648,8 +659,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;
}
@@ -666,9 +678,11 @@ FormatStyle getMozillaStyle() {
MozillaStyle.BinPackArguments = false;
MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
MozillaStyle.BreakConstructorInitializersBeforeComma = true;
+ MozillaStyle.BreakBeforeInheritanceComma = true;
MozillaStyle.ConstructorInitializerIndentWidth = 2;
MozillaStyle.ContinuationIndentWidth = 2;
MozillaStyle.Cpp11BracedListStyle = false;
+ MozillaStyle.FixNamespaceComments = false;
MozillaStyle.IndentCaseLabels = true;
MozillaStyle.ObjCSpaceAfterProperty = true;
MozillaStyle.ObjCSpaceBeforeProtocolList = false;
@@ -689,6 +703,7 @@ FormatStyle getWebKitStyle() {
Style.BreakConstructorInitializersBeforeComma = true;
Style.Cpp11BracedListStyle = false;
Style.ColumnLimit = 0;
+ Style.FixNamespaceComments = false;
Style.IndentWidth = 4;
Style.NamespaceIndentation = FormatStyle::NI_Inner;
Style.ObjCBlockIndentWidth = 4;
@@ -706,6 +721,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;
@@ -1457,12 +1473,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 +1557,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 +1567,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 +1671,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;
@@ -1808,23 +1834,36 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
FormatStyle Expanded = expandPresets(Style);
if (Expanded.DisableFormat)
return tooling::Replacements();
-
+ if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
+ return tooling::Replacements();
auto Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
- 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);
+ auto reformatAfterApplying = [&] (TokenAnalyzer& Fixer) {
+ tooling::Replacements Fixes = Fixer.process();
+ if (!Fixes.empty()) {
+ auto NewCode = applyAllReplacements(Code, Fixes);
if (NewCode) {
auto NewEnv = Environment::CreateVirtualEnvironment(
*NewCode, FileName,
- tooling::calculateRangesAfterReplacements(Requotes, Ranges));
+ tooling::calculateRangesAfterReplacements(Fixes, Ranges));
Formatter Format(*NewEnv, Expanded, IncompleteFormat);
- return Requotes.merge(Format.process());
+ return Fixes.merge(Format.process());
}
}
+ Formatter Format(*Env, Expanded, IncompleteFormat);
+ return Format.process();
+ };
+
+ if (Style.Language == FormatStyle::LK_Cpp &&
+ Style.FixNamespaceComments) {
+ NamespaceEndCommentsFixer CommentsFixer(*Env, Expanded);
+ return reformatAfterApplying(CommentsFixer);
+ }
+
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) {
+ JavaScriptRequoter Requoter(*Env, Expanded);
+ return reformatAfterApplying(Requoter);
}
Formatter Format(*Env, Expanded, IncompleteFormat);
@@ -1840,13 +1879,24 @@ tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
return Clean.process();
}
+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();
+}
+
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 +1932,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 +1948,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 +1986,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 +2011,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/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index ea3bbe368d5b..c9649126d93f 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -48,11 +48,13 @@ namespace format {
TYPE(FunctionTypeLParen) \
TYPE(ImplicitStringLiteral) \
TYPE(InheritanceColon) \
+ TYPE(InheritanceComma) \
TYPE(InlineASMBrace) \
TYPE(InlineASMColon) \
TYPE(JavaAnnotation) \
TYPE(JsComputedPropertyName) \
TYPE(JsFatArrow) \
+ TYPE(JsNonNullAssertion) \
TYPE(JsTypeColon) \
TYPE(JsTypeOperator) \
TYPE(JsTypeOptionalQuestion) \
@@ -220,6 +222,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 +263,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 +344,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,6 +457,8 @@ 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) ||
@@ -451,6 +467,8 @@ struct FormatToken {
/// \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);
}
@@ -618,6 +636,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");
@@ -644,6 +664,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;
diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp
index 46a32a917dd9..4ee43d6937e0 100644
--- a/lib/Format/FormatTokenLexer.cpp
+++ b/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};
@@ -82,6 +84,35 @@ void FormatTokenLexer::tryMergePreviousTokens() {
if (tryMergeTokens(JSRightArrow, TT_JsFatArrow))
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() {
@@ -157,7 +188,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
@@ -558,8 +591,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/lib/Format/FormatTokenLexer.h b/lib/Format/FormatTokenLexer.h
index c47b0e725d36..bf10f09cd11e 100644
--- a/lib/Format/FormatTokenLexer.h
+++ b/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/lib/Format/NamespaceEndCommentsFixer.cpp b/lib/Format/NamespaceEndCommentsFixer.cpp
new file mode 100644
index 000000000000..88cf123c1899
--- /dev/null
+++ b/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -0,0 +1,175 @@
+//===--- 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";
+ }
+}
+} // 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;
+ for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
+ if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective ||
+ !AnnotatedLines[I]->startsWith(tok::r_brace))
+ continue;
+ const AnnotatedLine *EndLine = AnnotatedLines[I];
+ size_t StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
+ if (StartLineIndex == UnwrappedLine::kInvalidIndex)
+ continue;
+ assert(StartLineIndex < E);
+ 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))
+ 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;
+ }
+ // 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 NamespaceName = computeName(NamespaceTok);
+ const std::string EndCommentText =
+ computeEndCommentText(NamespaceName, AddNewline);
+ if (!hasEndComment(EndCommentPrevTok)) {
+ bool isShort = I - StartLineIndex <= kShortNamespaceMaxLines + 1;
+ if (!isShort)
+ addEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
+ continue;
+ }
+ if (!validEndComment(EndCommentPrevTok, NamespaceName))
+ updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
+ }
+ return Fixes;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/NamespaceEndCommentsFixer.h b/lib/Format/NamespaceEndCommentsFixer.h
new file mode 100644
index 000000000000..7790668a2e82
--- /dev/null
+++ b/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/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index b5f7de280acd..004800fc2a4e 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -311,14 +311,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 +336,9 @@ private:
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->Type = TT_JsComputedPropertyName;
+ } 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,
@@ -433,9 +435,7 @@ private:
if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) {
FormatToken *Previous = CurrentToken->getPreviousNonComment();
if (((CurrentToken->is(tok::colon) &&
- (!Contexts.back().ColonIsDictLiteral ||
- (Style.Language != FormatStyle::LK_Cpp &&
- Style.Language != FormatStyle::LK_ObjC))) ||
+ (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
Style.Language == FormatStyle::LK_Proto) &&
(Previous->Tok.getIdentifierInfo() ||
Previous->is(tok::string_literal)))
@@ -676,6 +676,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 +686,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;
}
@@ -727,6 +735,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 +793,14 @@ private:
default:
break;
}
- while (CurrentToken)
+ while (CurrentToken) {
+ FormatToken *Tok = CurrentToken;
next();
+ if (Tok->isOneOf(Keywords.kw___has_include,
+ Keywords.kw___has_include_next)) {
+ parseHasInclude();
+ }
+ }
return Type;
}
@@ -885,7 +907,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 +947,7 @@ private:
bool CanBeExpression = true;
bool InTemplateArgument = false;
bool InCtorInitializer = false;
+ bool InInheritanceList = false;
bool CaretFound = false;
bool IsForEachMacro = false;
};
@@ -984,6 +1007,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 +1030,23 @@ 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::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 +1106,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)) {
@@ -1076,21 +1120,17 @@ private:
}
}
} 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;
- }
+ 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 +1177,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 +1216,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 +1321,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;
@@ -1445,7 +1485,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 +1496,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();
}
@@ -1493,13 +1537,14 @@ private:
return prec::Conditional;
if (NextNonComment && NextNonComment->is(tok::colon) &&
NextNonComment->is(TT_DictLiteral))
- return prec::Comma;
+ 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 +1555,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,8 +1639,14 @@ 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)
+ bool CommentLine = (*I)->First;
+ for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) {
+ if (!Tok->is(tok::comment)) {
+ CommentLine = false;
+ break;
+ }
+ }
+ if (NextNonCommentLine && CommentLine)
(*I)->Level = NextNonCommentLine->Level;
else
NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr;
@@ -1697,7 +1748,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 +1762,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 +1808,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 +1883,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); });
@@ -1910,7 +1972,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) ||
@@ -2167,7 +2229,7 @@ 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) {
@@ -2181,6 +2243,14 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
} else if (Style.Language == FormatStyle::LK_JavaScript) {
if (Left.is(TT_JsFatArrow))
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;
@@ -2196,8 +2266,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 +2301,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))
@@ -2302,12 +2373,16 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
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)) ||
@@ -2375,6 +2450,11 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
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
@@ -2398,9 +2478,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 &&
@@ -2416,6 +2493,10 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
Style.BreakConstructorInitializersBeforeComma &&
!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
@@ -2458,11 +2539,10 @@ 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)))
+ if (NonComment &&
+ NonComment->isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break,
+ tok::kw_throw, Keywords.kw_interface,
+ Keywords.kw_type))
return false; // Otherwise a semicolon is inserted.
if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace))
return false;
@@ -2476,6 +2556,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 +2569,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))
@@ -2590,6 +2677,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Right.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializersBeforeComma)
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)))
return false;
@@ -2615,7 +2706,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 +2719,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/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index 97daaf44ba99..805509533bf9 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/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/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index d7f1c4232d86..c3c154afeb8a 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -530,34 +530,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;
}
@@ -841,8 +840,7 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
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 +880,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 +901,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 +940,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/lib/Format/UnwrappedLineFormatter.h b/lib/Format/UnwrappedLineFormatter.h
index 7bcead9d25e1..93247f71d6e0 100644
--- a/lib/Format/UnwrappedLineFormatter.h
+++ b/lib/Format/UnwrappedLineFormatter.h
@@ -44,9 +44,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,7 +56,8 @@ 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;
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 8fc3b78aee01..5be68ad5c6b8 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -202,7 +202,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() {
@@ -334,8 +335,11 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
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.
+ // 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
Tok->BlockKind = BK_Unknown;
@@ -424,6 +428,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
parseParens();
addUnwrappedLine();
+ size_t OpeningLineIndex =
+ Lines.empty() ? (UnwrappedLine::kInvalidIndex) : (Lines.size() - 1);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
@@ -449,6 +455,7 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
if (MunchSemi && FormatTok->Tok.is(tok::semi))
nextToken();
Line->Level = InitialLevel;
+ Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
}
static bool isGoogScope(const UnwrappedLine &Line) {
@@ -582,13 +589,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();
}
@@ -746,8 +754,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();
}
@@ -909,7 +916,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)) {
@@ -943,7 +951,7 @@ void UnwrappedLineParser::parseStructuralElement() {
if (!parseEnum())
break;
// This only applies for C++.
- if (Style.Language != FormatStyle::LK_Cpp) {
+ if (!Style.isCpp()) {
addUnwrappedLine();
return;
}
@@ -1124,7 +1132,7 @@ void UnwrappedLineParser::parseStructuralElement() {
}
bool UnwrappedLineParser::tryToParseLambda() {
- if (Style.Language != FormatStyle::LK_Cpp) {
+ if (!Style.isCpp()) {
nextToken();
return false;
}
@@ -1298,6 +1306,12 @@ 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();
+ }
}
switch (FormatTok->Tok.getKind()) {
case tok::caret:
@@ -1309,12 +1323,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,6 +1333,12 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
break;
}
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::r_brace:
nextToken();
return !HasError;
@@ -1381,6 +1395,12 @@ void UnwrappedLineParser::parseParens() {
if (FormatTok->Tok.is(tok::l_brace))
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 &&
(FormatTok->is(Keywords.kw_function) ||
@@ -1722,8 +1742,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;
}
}
@@ -1819,7 +1838,7 @@ void UnwrappedLineParser::parseJavaEnumBody() {
addUnwrappedLine();
}
-void UnwrappedLineParser::parseRecord() {
+void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
const FormatToken &InitialToken = *FormatTok;
nextToken();
@@ -1863,11 +1882,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;",
@@ -1999,7 +2022,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 +2049,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 +2065,139 @@ bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
FormatTok.NewlinesBefore > 0;
}
+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
+// section on \p Line.
+static bool continuesLineComment(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;
+ }
+
+ unsigned MinContinueColumn =
+ MinColumnToken->OriginalColumn +
+ (isLineComment(*MinColumnToken) ? 0 : 1);
+ return isLineComment(FormatTok) && FormatTok.NewlinesBefore == 1 &&
+ isLineComment(*(Line.Tokens.back().Tok)) &&
+ FormatTok.OriginalColumn >= MinContinueColumn;
+}
+
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 =
+ continuesLineComment(**I, *Line, CommentPragmasRegex);
+ if (isOnNewLine(**I) && JustComments && !(*I)->ContinuesLineCommentSection)
addUnwrappedLine();
pushToken(*I);
}
@@ -2073,13 +2225,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 continuesLineComment, 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 =
+ continuesLineComment(*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 +2319,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/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 9c78d33632c6..15d1d9cda7a2 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/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 {
@@ -99,7 +108,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 +125,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 +189,8 @@ private:
const FormatStyle &Style;
const AdditionalKeywords &Keywords;
+ llvm::Regex CommentPragmasRegex;
+
FormatTokenSource *Tokens;
UnwrappedLineConsumer &Callback;
@@ -213,8 +242,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/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index b64506f39035..2c1f59324971 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/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() {
@@ -125,30 +121,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 +192,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].nestingAndIndentLevel() <
+ Changes[ScopeStack.back()].nestingAndIndentLevel())
+ ScopeStack.pop_back();
+
+ if (i != Start && Changes[i].nestingAndIndentLevel() >
+ Changes[i - 1].nestingAndIndentLevel())
+ 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 +249,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 +287,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 NestingAndIndentLevel = StartAt < Changes.size()
+ ? Changes[StartAt].nestingAndIndentLevel()
+ : 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 +319,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].nestingAndIndentLevel() < NestingAndIndentLevel)
+ break;
+
if (Changes[i].NewlinesBefore != 0) {
CommasBeforeMatch = 0;
EndOfSequence = i;
@@ -247,33 +335,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].nestingAndIndentLevel() > NestingAndIndentLevel) {
+ // 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 +375,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 +394,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 +409,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() {
@@ -360,17 +446,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(
@@ -481,7 +564,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);
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index f42e371830b3..6be4af262276 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -43,8 +43,7 @@ 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,
+ void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces,
unsigned StartOfTokenColumn,
bool InPPDirective = false);
@@ -72,8 +71,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 +89,6 @@ public:
const SourceManager &SourceMgr;
};
- Change() {}
-
/// \brief Creates a \c Change.
///
/// The generated \c Change will replace the characters at
@@ -102,12 +98,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 +118,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 +149,14 @@ public:
// the alignment process.
const Change *StartOfBlockComment;
int IndentationOffset;
+
+ // A combination of nesting level and indent 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>
+ nestingAndIndentLevel() const {
+ return std::make_pair(Tok->NestingLevel, Tok->IndentLevel);
+ }
};
private:
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index d8118cb30f63..720baa5e0f7a 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/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);
+ 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/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index d8929969e6c1..2acdc6494f85 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/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"
@@ -185,7 +186,8 @@ 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() {
@@ -619,6 +621,10 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
StoredDiags.emplace_back(Level, Info);
}
+IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const {
+ return Reader;
+}
+
ASTMutationListener *ASTUnit::getASTMutationListener() {
if (WriterData)
return &WriterData->Writer;
@@ -677,6 +683,7 @@ 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,
@@ -697,7 +704,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
AST->PP = std::make_shared<Preprocessor>(
std::move(PPOpts), AST->getDiagnostics(), AST->ASTFileLangOpts,
- AST->getSourceManager(), HeaderInfo, *AST,
+ AST->getSourceManager(), *AST->PCMCache, HeaderInfo, *AST,
/*IILookup=*/nullptr,
/*OwnsHeaderSearch=*/false);
Preprocessor &PP = *AST->PP;
@@ -1245,7 +1252,7 @@ ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) {
PreambleFileHash Result;
Result.Size = Size;
Result.ModTime = ModTime;
- memset(Result.MD5, 0, sizeof(Result.MD5));
+ Result.MD5 = {};
return Result;
}
@@ -1266,7 +1273,7 @@ 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;
+ LHS.MD5 == RHS.MD5;
}
} // namespace clang
@@ -1723,6 +1730,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;
}
@@ -1879,6 +1887,7 @@ bool ASTUnit::LoadFromCompilerInvocation(
// 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;
@@ -1886,6 +1895,8 @@ bool ASTUnit::LoadFromCompilerInvocation(
PreambleRebuildCounter = PrecompilePreambleAfterNParses;
OverrideMainBuffer =
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
}
SimpleTimer ParsingTimer(WantTiming);
@@ -1990,6 +2001,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
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 +2013,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;
@@ -2516,7 +2528,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);
}
@@ -2534,6 +2547,8 @@ void ASTUnit::TranslateStoredDiagnostics(
SmallVector<StoredDiagnostic, 4> Result;
Result.reserve(Diags.size());
+ const FileEntry *PreviousFE = nullptr;
+ FileID FID;
for (const StandaloneDiagnostic &SD : Diags) {
// Rebuild the StoredDiagnostic.
if (SD.Filename.empty())
@@ -2541,7 +2556,10 @@ void ASTUnit::TranslateStoredDiagnostics(
const FileEntry *FE = FileMgr.getFile(SD.Filename);
if (!FE)
continue;
- FileID FID = SrcMgr.translateFile(FE);
+ if (FE != PreviousFE) {
+ FID = SrcMgr.translateFile(FE);
+ PreviousFE = FE;
+ }
SourceLocation FileLoc = SrcMgr.getLocForStartOfFile(FID);
if (FileLoc.isInvalid())
continue;
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index afcaa6e87878..8b4b16920668 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/Decl.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 +56,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 +135,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 +379,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 +497,8 @@ void CompilerInstance::createPCHExternalASTSource(
AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(),
getPCHContainerReader(),
getFrontendOpts().ModuleFileExtensions,
+ TheDependencyFileGenerator.get(),
+ DependencyCollectors,
DeserializationListener,
OwnDeserializationListener, Preamble,
getFrontendOpts().UseGlobalModuleIndex);
@@ -501,6 +509,8 @@ 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();
@@ -518,6 +528,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,
@@ -1032,7 +1048,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) {
@@ -1063,6 +1079,8 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
FrontendOpts.DisableFree = false;
FrontendOpts.GenerateGlobalModuleIndex = false;
FrontendOpts.BuildingImplicitModule = true;
+ // Force implicitly-built modules to hash the content of the module file.
+ HSOpts.ModulesHashContent = true;
FrontendOpts.Inputs.clear();
InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
@@ -1074,9 +1092,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));
@@ -1180,10 +1200,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 +1227,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;
}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 36f6b0a5111a..ab9f20304c9c 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -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>
@@ -505,6 +516,7 @@ 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.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
@@ -544,6 +556,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 =
@@ -570,7 +584,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 +596,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 +626,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)
@@ -631,12 +649,14 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
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.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)
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);
@@ -709,21 +729,28 @@ 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);
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);
@@ -801,18 +828,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")
@@ -1123,6 +1138,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 +1257,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);
@@ -1407,7 +1424,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 +1435,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 +1525,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 +1558,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,
@@ -1579,7 +1605,11 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
case IK_PreprocessedCXX:
case IK_ObjCXX:
case IK_PreprocessedObjCXX:
- LangStd = LangStandard::lang_gnucxx98;
+ // 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:
LangStd = LangStandard::lang_c99;
@@ -1602,7 +1632,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.ImplicitInt = Std.hasImplicitInt();
// Set OpenCL Version.
- Opts.OpenCL = isOpenCL(LangStd) || IK == IK_OpenCL;
+ Opts.OpenCL = Std.isOpenCL() || IK == IK_OpenCL;
if (LangStd == LangStandard::lang_opencl)
Opts.OpenCLVersion = 100;
else if (LangStd == LangStandard::lang_opencl11)
@@ -1616,9 +1646,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.
@@ -1629,6 +1658,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda ||
LangStd == LangStandard::lang_cuda;
+ if (Opts.CUDA)
+ // Set default FP_CONTRACT to FAST.
+ Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
Opts.RenderScript = IK == IK_RenderScript;
if (Opts.RenderScript) {
@@ -1671,6 +1703,63 @@ 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) {
+ case IK_C:
+ case IK_ObjC:
+ case IK_PreprocessedC:
+ case IK_PreprocessedObjC:
+ if (S.isC89() || S.isC99())
+ return true;
+ break;
+ case IK_CXX:
+ case IK_ObjCXX:
+ case IK_PreprocessedCXX:
+ case IK_PreprocessedObjCXX:
+ if (S.isCPlusPlus())
+ return true;
+ break;
+ case IK_OpenCL:
+ if (S.isOpenCL())
+ return true;
+ break;
+ case IK_CUDA:
+ case IK_PreprocessedCuda:
+ if (S.isCPlusPlus())
+ return true;
+ break;
+ default:
+ // For other inputs, accept (and ignore) all -std= values.
+ return true;
+ }
+ return false;
+}
+
+/// Get language name for given input kind.
+static const StringRef GetInputKindName(InputKind IK) {
+ switch (IK) {
+ case IK_C:
+ case IK_ObjC:
+ case IK_PreprocessedC:
+ case IK_PreprocessedObjC:
+ return "C/ObjC";
+ case IK_CXX:
+ case IK_ObjCXX:
+ case IK_PreprocessedCXX:
+ case IK_PreprocessedObjCXX:
+ return "C++/ObjC++";
+ case IK_OpenCL:
+ return "OpenCL";
+ case IK_CUDA:
+ case IK_PreprocessedCuda:
+ return "CUDA";
+ default:
+ llvm_unreachable("Cannot decide on name for InputKind!");
+ }
+}
+
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
const TargetOptions &TargetOpts,
PreprocessorOptions &PPOpts,
@@ -1685,43 +1774,27 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
.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)) {
+ Diags.Report(diag::note_drv_use_standard)
+ << Std.getName() << Std.getDescription();
+ }
+ }
+ } 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 +1803,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_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);
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 +1913,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 +1931,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 +2017,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);
@@ -2045,12 +2117,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)
@@ -2214,6 +2280,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,6 +2314,16 @@ 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);
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
@@ -2251,6 +2339,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))
@@ -2405,7 +2494,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,7 +2529,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseTargetArgs(Res.getTargetOpts(), Args, Diags);
Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags,
Res.getTargetOpts());
- ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args);
+ ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args,
+ Res.getFileSystemOpts().WorkingDir);
if (DashX == IK_AST || DashX == IK_LLVM_IR) {
// ObjCAAutoRefCount and Sanitize LangOpts are used to setup the
// PassManager in BackendUtil.cpp. They need to be initializd no matter
@@ -2466,10 +2556,6 @@ 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);
}
// FIXME: Override value name discarding when asan or msan is used because the
@@ -2569,29 +2655,6 @@ 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);
- }
- }
-
return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 39fc1371a9ef..0dd07d9f817b 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/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"
@@ -187,6 +188,42 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
}
+// For preprocessed files, if the first line is the linemarker and specifies
+// the original source file name, use that name as the input file name.
+static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile)
+{
+ bool Invalid = false;
+ auto &SourceMgr = CI.getSourceManager();
+ auto MainFileID = SourceMgr.getMainFileID();
+ const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid);
+ if (Invalid)
+ return false;
+
+ 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 false;
+ if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() ||
+ T.getKind() != tok::numeric_constant)
+ return false;
+ RawLexer->LexFromRawLexer(T);
+ if (T.isAtStartOfLine() || T.getKind() != tok::string_literal)
+ return false;
+
+ StringLiteralParser Literal(T, CI.getPreprocessor());
+ if (Literal.hadError)
+ return false;
+ InputFile = Literal.GetString().str();
+ return true;
+}
+
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
const FrontendInputFile &Input) {
assert(!Instance && "Already processing a source file!");
@@ -225,6 +262,9 @@ 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));
@@ -335,6 +375,13 @@ 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 OrigFile;
+ if (Input.isPreprocessed())
+ if (ReadOriginalFileName(CI, OrigFile))
+ InputFile = OrigFile;
+
std::unique_ptr<ASTConsumer> Consumer =
CreateWrappedASTConsumer(CI, InputFile);
if (!Consumer)
@@ -352,8 +399,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 +418,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 +445,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 +474,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);
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index f795a1d0475a..e818038b1354 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/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,6 +128,12 @@ GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
return OS;
}
+bool GeneratePCHAction::shouldEraseOutputFiles() {
+ if (getCompilerInstance().getPreprocessorOpts().AllowPCHWithCompilerErrors)
+ return false;
+ return ASTFrontendAction::shouldEraseOutputFiles();
+}
+
bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) {
CI.getLangOpts().CompilingPCH = true;
@@ -567,6 +574,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]");
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 17603ada11d1..88be7732f519 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -374,9 +374,11 @@ 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.
+ // C++17 [cpp.predefined]p1:
+ // The name __cplusplus is defined to the value 201703L when compiling a
+ // C++ translation unit.
if (LangOpts.CPlusPlus1z)
- Builder.defineMacro("__cplusplus", "201406L");
+ 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 +477,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");
@@ -522,6 +525,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_structured_bindings", "201606");
Builder.defineMacro("__cpp_nontype_template_args", "201411");
Builder.defineMacro("__cpp_fold_expressions", "201603");
+ // FIXME: This is not yet listed in SD-6.
+ Builder.defineMacro("__cpp_deduction_guides", "201611");
}
if (LangOpts.AlignedAllocation)
Builder.defineMacro("__cpp_aligned_new", "201606");
@@ -593,9 +598,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 +628,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);
diff --git a/lib/Frontend/Rewrite/RewriteMacros.cpp b/lib/Frontend/Rewrite/RewriteMacros.cpp
index 0d0a991fa6f9..ae6b51bc814f 100644
--- a/lib/Frontend/Rewrite/RewriteMacros.cpp
+++ b/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/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index e7bfcedd2176..83290a6fbc28 100644
--- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -4454,7 +4454,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 +5141,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;
@@ -7500,7 +7500,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/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index e842e592cbbe..7d809c610c86 100644
--- a/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -2992,7 +2992,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 +3629,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 +4261,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;
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 187a6e76245d..1f7493c9e398 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -174,7 +174,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/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index efc4dd0971b6..35aff4017e93 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -28,6 +28,7 @@ set(files
__clang_cuda_intrinsics.h
__clang_cuda_math_forward_declares.h
__clang_cuda_runtime_wrapper.h
+ clzerointrin.h
cpuid.h
clflushoptintrin.h
emmintrin.h
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index a01d9d837ad1..421e2a7754a5 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -8045,45 +8045,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
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index 13bcbef4dbbe..5d83a8db484b 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -832,7 +832,7 @@ _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);
+ return (__m256i)__builtin_nontemporal_load((const __v4di *)__V);
}
static __inline__ __m128 __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/avx512bwintrin.h b/lib/Headers/avx512bwintrin.h
index 629dc8611a7f..41958b7214e2 100644
--- a/lib/Headers/avx512bwintrin.h
+++ b/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/lib/Headers/avx512dqintrin.h b/lib/Headers/avx512dqintrin.h
index ae44b98a9495..4fd1add7735b 100644
--- a/lib/Headers/avx512dqintrin.h
+++ b/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/lib/Headers/avx512fintrin.h b/lib/Headers/avx512fintrin.h
index e6a7217c8967..d8535f765889 100644
--- a/lib/Headers/avx512fintrin.h
+++ b/lib/Headers/avx512fintrin.h
@@ -4229,6 +4229,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 +4552,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 +4561,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 +4570,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 +4596,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 +7290,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 +7862,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 +7880,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 +8161,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 +8860,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 +8872,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)
{
@@ -8925,7 +8931,7 @@ _mm512_stream_si512 (__m512i * __P, __m512i __A)
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_stream_load_si512 (void *__P)
{
- return __builtin_ia32_movntdqa512 ((__v8di *)__P);
+ return (__m512i) __builtin_nontemporal_load((const __v8di *)__P);
}
static __inline__ void __DEFAULT_FN_ATTRS
@@ -9635,6 +9641,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,
diff --git a/lib/Headers/avx512vldqintrin.h b/lib/Headers/avx512vldqintrin.h
index cd9da4370564..aecd7df34d05 100644
--- a/lib/Headers/avx512vldqintrin.h
+++ b/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/lib/Headers/avx512vlintrin.h b/lib/Headers/avx512vlintrin.h
index f3744da6ab8a..99bb050de4d7 100644
--- a/lib/Headers/avx512vlintrin.h
+++ b/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/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index be03ba346031..5381878a5da3 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -1613,9 +1613,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 +1628,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) */
@@ -1660,17 +1660,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), \
@@ -1697,17 +1718,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), \
@@ -1734,17 +1776,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), \
@@ -1771,17 +1834,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), \
@@ -1807,17 +1891,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), \
@@ -1843,17 +1948,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 +2310,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 +2343,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)
{
diff --git a/lib/Headers/clzerointrin.h b/lib/Headers/clzerointrin.h
new file mode 100644
index 000000000000..ed7478ff87ea
--- /dev/null
+++ b/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/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 1512f9f0b47b..0dfa6a9fbc1f 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -1599,6 +1599,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 __dp
+/// 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 +1620,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
+/// An 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)
{
@@ -1787,7 +1809,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.
@@ -2369,7 +2391,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.
///
@@ -4019,7 +4041,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 +4163,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 +4810,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/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h
index 180712ffc680..b796cc84316f 100644
--- a/lib/Headers/f16cintrin.h
+++ b/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/lib/Headers/htmxlintrin.h b/lib/Headers/htmxlintrin.h
index 16dc7056c6b0..28f7d025bb30 100644
--- a/lib/Headers/htmxlintrin.h
+++ b/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/lib/Headers/intrin.h b/lib/Headers/intrin.h
index a35262af846a..38d9407abed9 100644
--- a/lib/Headers/intrin.h
+++ b/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,7 +79,6 @@ 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);
@@ -142,7 +140,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 +173,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);
@@ -372,11 +368,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 +863,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/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h
index e0c277a65a33..2b3618398cbf 100644
--- a/lib/Headers/mmintrin.h
+++ b/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
diff --git a/lib/Headers/module.modulemap b/lib/Headers/module.modulemap
index 11ef2f902945..95d26cefa6f7 100644
--- a/lib/Headers/module.modulemap
+++ b/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/lib/Headers/opencl-c.h b/lib/Headers/opencl-c.h
index 0c25d312709d..6452d5c987f0 100644
--- a/lib/Headers/opencl-c.h
+++ b/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
@@ -15995,9 +15307,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);
@@ -16025,16 +15339,20 @@ 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
// 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,9 +15380,11 @@ 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);
@@ -16091,16 +15411,20 @@ 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
// 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 +15442,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 +15461,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 +15514,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,7 +15550,9 @@ 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);
@@ -16238,7 +15570,9 @@ 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);
@@ -16324,7 +15658,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 +15754,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 +15842,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 +16054,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/lib/Headers/pmmintrin.h b/lib/Headers/pmmintrin.h
index d4f6487af179..a479d9ed2911 100644
--- a/lib/Headers/pmmintrin.h
+++ b/lib/Headers/pmmintrin.h
@@ -115,7 +115,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 +136,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 +257,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/lib/Headers/prfchwintrin.h b/lib/Headers/prfchwintrin.h
index ba0285751823..a3789126ef07 100644
--- a/lib/Headers/prfchwintrin.h
+++ b/lib/Headers/prfchwintrin.h
@@ -29,12 +29,36 @@
#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/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index e48ab034f46f..dccba4e40b2d 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -46,37 +46,394 @@
#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> <i> VROUNDPS / ROUNDPS </i> </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> <i> VROUNDPD / ROUNDPD </i> </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> <i> VROUNDSS / ROUNDSS </i> </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> <i> VROUNDSD / ROUNDSD </i> </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> <i> VROUNDPS / ROUNDPS </i> </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> <i> VROUNDPD / ROUNDPD </i> </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> <i> VROUNDSS / ROUNDSS </i> </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> <i> VROUNDSD / ROUNDSD </i> </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> <i> VROUNDPS / ROUNDPS </i> </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> <i> VROUNDSS / ROUNDSS </i> </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> <i> VROUNDPD / ROUNDPD </i> </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> <i> VROUNDSD / ROUNDSD </i> </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> <i> VBLENDPD / BLENDPD </i> </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> <i> VBLENDPS / BLENDPS </i> </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 +441,27 @@
(((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> <i> VBLENDVPD / BLENDVPD </i> </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 +469,27 @@ _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> <i> VBLENDVPS / BLENDVPS </i> </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 +497,27 @@ _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> <i> VPBLENDVB / PBLENDVB </i> </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 +525,31 @@ _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> <i> VPBLENDW / PBLENDW </i> </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 +563,41 @@ _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> <i> VPMULLD / PMULLD </i> </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> <i> VPMULDQ / PMULDQ </i> </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 +605,250 @@ _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> <i> VDPPS / DPPS </i> </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> <i> VDPPD / DPPD </i> </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> <i> VMOVNTDQA / MOVNTDQA </i> </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> <i> VPMINSB / PMINSB </i> </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> <i> VPMAXSB / PMAXSB </i> </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> <i> VPMINUW / PMINUW </i> </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> <i> VPMAXUW / PMAXUW </i> </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> <i> VPMINSD / PMINSD </i> </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> <i> VPMAXSD / PMAXSD </i> </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> <i> VPMINUD / PMINUD </i> </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> <i> VPMAXUD / PMAXUD </i> </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 +856,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> <i> VINSERTPS </i> </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> <i> VEXTRACTPS / EXTRACTPS </i> </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 +940,113 @@ _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> <i> VPINSRB / PINSRB </i> </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> <i> VPINSRD / PINSRD </i> </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.
+/// 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> <i> VPINSRQ / PINSRQ </i> </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.
+/// 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 +1056,228 @@ _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> <i> VPEXTRB / PEXTRB </i> </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> <i> VPEXTRD / PEXTRD </i> </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> <i> VPEXTRQ / PEXTRQ </i> </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> <i> VPTEST / PTEST </i> </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> <i> VPTEST / PTEST </i> </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> <i> VPTEST / PTEST </i> </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> <i> VPTEST / PTEST </i> </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> <i> VPTEST / PTEST </i> </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> <i> VPTEST / PTEST </i> </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> <i> VPCMPEQQ / PCMPEQQ </i> </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 +1285,20 @@ _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> <i> VPMOVSXBW / PMOVSXBW </i> </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 +1307,20 @@ _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> <i> VPMOVSXBD / PMOVSXBD </i> </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 +1329,20 @@ _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> <i> VPMOVSXBQ / PMOVSXBQ </i> </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 +1351,60 @@ _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> <i> VPMOVSXWD / PMOVSXWD </i> </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> <i> VPMOVSXWQ / PMOVSXWQ </i> </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> <i> VPMOVSXDQ / PMOVSXDQ </i> </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 +1412,120 @@ _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> <i> VPMOVZXBW / PMOVZXBW </i> </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> <i> VPMOVZXBD / PMOVZXBD </i> </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> <i> VPMOVZXBQ / PMOVZXBQ </i> </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> <i> VPMOVZXWD / PMOVZXWD </i> </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> <i> VPMOVZXWQ / PMOVZXWQ </i> </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> <i> VPMOVZXDQ / PMOVZXDQ </i> </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 +1533,29 @@ _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> <i> VPACKUSDW / PACKUSDW </i> </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 +1563,59 @@ _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> <i> VMPSADBW / MPSADBW </i> </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> <i> VPHMINPOSUW / PHMINPOSUW </i> </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 +1657,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> <i> VPCMPISTRM / PCMPISTRM </i> </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> <i> VPCMPISTRI / PCMPISTRI </i> </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> <i> VPCMPESTRM / PCMPESTRM </i> </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> <i> VPCMPESTRI / PCMPESTRI </i> </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> <i> VPCMPISTRI / PCMPISTRI </i> </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> <i> VPCMPISTRI / PCMPISTRI </i> </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> <i> VPCMPISTRI / PCMPISTRI </i> </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> <i> VPCMPISTRI / PCMPISTRI </i> </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> <i> VPCMPISTRI / PCMPISTRI </i> </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> <i> VPCMPESTRI / PCMPESTRI </i> </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> <i> VPCMPESTRI / PCMPESTRI </i> </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> <i> VPCMPESTRI / PCMPESTRI </i> </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> <i> VPCMPESTRI / PCMPESTRI </i> </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> <i> VPCMPESTRI </i> </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> <i> VPCMPGTQ / PCMPGTQ </i> </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 +2427,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> <i> CRC32B </i> </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> <i> CRC32W </i> </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> <i> CRC32L </i> </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 +2488,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> <i> CRC32Q </i> </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/lib/Headers/stdarg.h b/lib/Headers/stdarg.h
index a57e18364871..101426fff151 100644
--- a/lib/Headers/stdarg.h
+++ b/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/lib/Headers/tgmath.h b/lib/Headers/tgmath.h
index 318e1185feee..34e26dcc05ec 100644
--- a/lib/Headers/tgmath.h
+++ b/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/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index 81a404f55d01..2003029cb5a8 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -80,6 +80,10 @@
#include <mwaitxintrin.h>
#endif
+#if !defined(_MSC_VER) || __has_feature(modules) || defined(__CLZERO__)
+#include <clzerointrin.h>
+#endif
+
/* FIXME: LWP */
#endif /* __X86INTRIN_H */
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index dc31b85cfd7c..bb8e29cd9052 100644
--- a/lib/Headers/xmmintrin.h
+++ b/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
@@ -2435,17 +2435,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 +2468,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 +2517,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"
diff --git a/lib/Headers/xopintrin.h b/lib/Headers/xopintrin.h
index bdf0cec32645..4a34f770d58d 100644
--- a/lib/Headers/xopintrin.h
+++ b/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/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index 8f51ccb11e58..c9fbfafcf946 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -24,5 +24,6 @@ add_clang_library(clangIndex
clangFormat
clangFrontend
clangRewrite
+ clangSerialization
clangToolingCore
)
diff --git a/lib/Index/CommentToXML.cpp b/lib/Index/CommentToXML.cpp
index ee066cc6d985..08acc96c4efb 100644
--- a/lib/Index/CommentToXML.cpp
+++ b/lib/Index/CommentToXML.cpp
@@ -593,9 +593,11 @@ void CommentASTToXMLConverter::formatTextOfDeclaration(
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",
+ &IncompleteFormat);
auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces);
if (static_cast<bool>(FormattedStringDecl)) {
Declaration = *FormattedStringDecl;
diff --git a/lib/Index/IndexBody.cpp b/lib/Index/IndexBody.cpp
index 3aa0152ec996..7f09290de40f 100644
--- a/lib/Index/IndexBody.cpp
+++ b/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)
@@ -178,7 +182,8 @@ public:
SymbolRoleSet Roles{};
SmallVector<SymbolRelation, 2> Relations;
addCallRole(Roles, Relations);
- if (E->isImplicit())
+ Stmt *Containing = getParentStmt();
+ if (E->isImplicit() || (Containing && isa<PseudoObjectExpr>(Containing)))
Roles |= (unsigned)SymbolRole::Implicit;
if (isDynamic(E)) {
@@ -194,9 +199,12 @@ public:
}
bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- if (E->isExplicitProperty())
+ 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);
+ }
// No need to do a handleReference for the objc method, because there will
// be a message expr as part of PseudoObjectExpr.
@@ -269,7 +277,7 @@ public:
const Decl *D = *I;
if (!D)
continue;
- if (!IndexCtx.isFunctionLocalDecl(D))
+ if (!isFunctionLocalSymbol(D))
IndexCtx.indexTopLevelDecl(D);
}
diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp
index 3b4f3f81399d..dae0cdc0d9c9 100644
--- a/lib/Index/IndexDecl.cpp
+++ b/lib/Index/IndexDecl.cpp
@@ -98,7 +98,29 @@ public:
if (MethodLoc.isInvalid())
MethodLoc = D->getLocation();
- if (!IndexCtx.handleDecl(D, MethodLoc, (unsigned)SymbolRole::Dynamic, Relations))
+ 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);
+ }
+
+ if (!IndexCtx.handleDecl(D, MethodLoc, Roles, Relations))
return false;
IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>();
@@ -136,6 +158,9 @@ public:
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 +171,12 @@ 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());
+ }
}
if (D->isThisDeclarationADefinition()) {
@@ -178,14 +209,8 @@ 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;
@@ -206,8 +231,9 @@ public:
}
bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ if (!D->isTransparentTag())
+ if (!IndexCtx.handleDecl(D))
+ return false;
IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
return true;
}
@@ -228,14 +254,17 @@ public:
}
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;
@@ -244,12 +273,26 @@ public:
bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
if (D->isThisDeclarationADefinition()) {
TRY_TO(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,
@@ -261,7 +304,8 @@ public:
bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
if (D->isThisDeclarationADefinition()) {
TRY_TO(IndexCtx.handleDecl(D));
- TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
+ TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
+ /*superLoc=*/SourceLocation()));
TRY_TO(IndexCtx.indexDeclContext(D));
} else {
return IndexCtx.handleReference(D, D->getLocation(), nullptr,
@@ -281,12 +325,16 @@ public:
if (!IndexCtx.handleDecl(D))
return false;
- // 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);
}
@@ -305,7 +353,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;
}
@@ -355,32 +404,58 @@ 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))
+ 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;
+ }
+ if (!IndexCtx.handleDecl(D, Loc, Roles, Relations))
return false;
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);
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, SymbolRoleSet(SymbolRole::Implicit), {},
+ 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, SymbolRoleSet(SymbolRole::Implicit), {},
+ 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;
+ }
+ if(!IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles))
+ return false;
+ } else {
+ IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
+ D->getDeclContext(), SymbolRoleSet());
+ }
}
return true;
}
diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp
index 84984fce4dc7..fe3c17845daa 100644
--- a/lib/Index/IndexSymbol.cpp
+++ b/lib/Index/IndexSymbol.cpp
@@ -49,6 +49,37 @@ 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 (!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;
+}
+
SymbolInfo index::getSymbolInfo(const Decl *D) {
assert(D);
SymbolInfo Info;
@@ -57,6 +88,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 +129,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 +185,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);
@@ -275,11 +321,12 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
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);
@@ -301,6 +348,16 @@ void index::applyForEachSymbolRole(SymbolRoleSet Roles,
APPLY_FOR_ROLE(RelationIBTypeOf);
#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) {
@@ -378,6 +435,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");
}
@@ -415,6 +473,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 +493,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/lib/Index/IndexTypeSourceInfo.cpp b/lib/Index/IndexTypeSourceInfo.cpp
index 38bbb30fedf1..0645d5be5268 100644
--- a/lib/Index/IndexTypeSourceInfo.cpp
+++ b/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())
@@ -191,7 +209,7 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
}
void IndexingContext::indexTagDecl(const TagDecl *D) {
- if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
+ if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
return;
if (handleDecl(D)) {
diff --git a/lib/Index/IndexingAction.cpp b/lib/Index/IndexingAction.cpp
index d7442931523f..cac24d4b9c4c 100644
--- a/lib/Index/IndexingAction.cpp
+++ b/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,20 @@ void index::indexASTUnit(ASTUnit &Unit,
IndexCtx.setASTContext(Unit.getASTContext());
DataConsumer->initialize(Unit.getASTContext());
indexTranslationUnit(Unit, IndexCtx);
+ 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/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp
index 6dd6c0cfb28e..f393b11ab884 100644
--- a/lib/Index/IndexingContext.cpp
+++ b/lib/Index/IndexingContext.cpp
@@ -24,9 +24,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 +33,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 +50,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 +100,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 *
@@ -229,6 +204,50 @@ static const Decl *getCanonicalDecl(const Decl *D) {
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:
+ 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,
@@ -264,7 +283,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 +305,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 +332,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/lib/Index/IndexingContext.h b/lib/Index/IndexingContext.h
index dd1dd328cd44..933b0a2cda07 100644
--- a/lib/Index/IndexingContext.h
+++ b/lib/Index/IndexingContext.h
@@ -58,7 +58,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 +71,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);
diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp
index 58f61c3c65b7..73dddd9a8b36 100644
--- a/lib/Index/USRGeneration.cpp
+++ b/lib/Index/USRGeneration.cpp
@@ -310,7 +310,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 << '#';
@@ -521,7 +521,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 << '#';
@@ -654,7 +654,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;
@@ -911,21 +910,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/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index c667f4bf2207..4ee38719289b 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/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);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 6025a6675125..4c051939471c 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -3603,17 +3603,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/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 1488f624da64..4f3db8dd6436 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -554,16 +554,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;
@@ -1839,7 +1840,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
Module::UnresolvedHeaderDirective Header;
Header.FileName = Tok.getString();
Header.FileNameLoc = consumeToken();
-
+
// Check whether we already have an umbrella.
if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) {
Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
@@ -1859,19 +1860,25 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// Search for the header file within the search directory.
SmallString<128> FullPathName(Directory->getName());
unsigned FullPathLength = FullPathName.size();
-
+
if (ActiveModule->isPartOfFramework()) {
appendSubframeworkPaths(ActiveModule, RelativePathName);
-
+ unsigned RelativePathLength = RelativePathName.size();
+
// Check whether this file is in the public headers.
llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
llvm::sys::path::append(FullPathName, RelativePathName);
File = SourceMgr.getFileManager().getFile(FullPathName);
-
+
+ // Check whether this file is in the private headers.
if (!File) {
- // Check whether this file is in the private headers.
- // FIXME: Should we retain the subframework paths here?
- RelativePathName.clear();
+ // 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.
+ RelativePathName.resize(ActiveModule->IsFramework ? 0
+ : RelativePathLength);
FullPathName.resize(FullPathLength);
llvm::sys::path::append(RelativePathName, "PrivateHeaders",
Header.FileName);
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index 45bdce32062a..f5e8cdc25d38 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/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/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 322c5809cd2c..8a56ddf23699 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1976,21 +1976,24 @@ 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);
}
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index de166c75e2cb..358c96a78300 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -1746,6 +1746,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/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 100da514144a..f81eaa31e9e9 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -160,12 +160,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);
}
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 91319bedd6f0..babef5dcc7ca 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -70,15 +70,15 @@ 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),
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index c52b61e7e983..172b0edce5e4 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/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;
@@ -344,9 +344,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)) {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2d320878014b..1465d21ac5ee 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/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"
@@ -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:
@@ -2824,44 +2962,23 @@ 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 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.
//
- // - 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,
- //
- // 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;
@@ -2892,30 +3009,21 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
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
@@ -2996,6 +3104,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 +3162,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 +3188,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)
@@ -3951,8 +4095,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.
@@ -4673,7 +4817,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.
@@ -4694,6 +4838,10 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
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();
@@ -4761,13 +4909,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 +4937,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 +4965,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 +4986,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:
@@ -5309,21 +5472,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()) {
@@ -5409,6 +5580,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 +5930,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 +6287,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 +6440,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 +6576,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;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 3f1fe7e06fe3..b25152a3183e 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/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;
}
@@ -912,8 +935,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,7 +1100,7 @@ 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);
@@ -1124,10 +1148,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.
@@ -1144,10 +1168,11 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// 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 +1406,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,
@@ -1885,6 +1911,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
}
+ if (!TagOrTempResult.isInvalid())
+ // Delayed proccessing of attributes.
+ Actions.ProcessDeclAttributeDelayed(TagOrTempResult.get(), attrs.getList());
+
const char *PrevSpec = nullptr;
unsigned DiagID;
bool Result;
@@ -2283,7 +2313,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 +2459,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 +2491,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 +2899,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 +2991,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 +3069,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.
@@ -3381,7 +3410,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
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");
TemplateTypeTy = getTypeAnnotation(Tok);
}
@@ -3817,36 +3846,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;
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 852e2269393a..ad45ab114fde 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/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"
@@ -198,8 +198,8 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
// 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);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult LHS(ParseCastExpression(false, false, isTypeCast));
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
@@ -473,12 +473,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 +676,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
/// '__is_union'
///
/// [Clang] unary-type-trait:
+/// '__is_aggregate'
/// '__trivially_copyable'
///
/// binary-type-trait:
@@ -694,7 +697,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 +726,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.
@@ -798,6 +805,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);
@@ -1307,7 +1315,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();
@@ -1693,6 +1702,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/
getLangOpts().MicrosoftExt,
+ /*AllowDeductionGuide=*/false,
ObjectType, TemplateKWLoc, Name)) {
(void)Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
@@ -1875,9 +1885,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 +1899,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;
@@ -2349,6 +2361,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 +2574,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()) {
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 124266a42bd5..671a815911f3 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/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++");
@@ -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;
@@ -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;
@@ -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 ')'.
@@ -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) ||
@@ -2020,9 +2026,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 +2059,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 +2084,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 {
@@ -2155,7 +2161,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 +2438,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 +2449,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 +2478,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 +2487,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);
@@ -2569,7 +2585,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/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index fa6b75daed92..f48d01e0f630 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/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"
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 81761bf8d2d8..77e63efc065e 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/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)
@@ -1448,12 +1431,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 +1542,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 +2024,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 +2045,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 +2112,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 +2183,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
}
@@ -2314,16 +2284,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 +2337,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 +2397,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 +3534,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();
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index cab7d3432db3..dfb0438ba8ce 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/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"
@@ -806,7 +806,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;
@@ -1053,7 +1053,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,
@@ -1557,8 +1557,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.
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 89733237c153..c8de6b35f9ef 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/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"
@@ -86,6 +86,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,
@@ -266,6 +272,9 @@ void Parser::initializePragmaHandlers() {
NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
PP.AddPragmaHandler(NoUnrollHintHandler.get());
+
+ FPHandler.reset(new PragmaFPHandler());
+ PP.AddPragmaHandler("clang", FPHandler.get());
}
void Parser::resetPragmaHandlers() {
@@ -344,6 +353,9 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler(NoUnrollHintHandler.get());
NoUnrollHintHandler.reset();
+
+ PP.RemovePragmaHandler("clang", FPHandler.get());
+ FPHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -454,7 +466,21 @@ void Parser::HandlePragmaFPContract() {
tok::OnOffSwitch OOS =
static_cast<tok::OnOffSwitch>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
- Actions.ActOnPragmaFPContract(OOS);
+
+ 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);
ConsumeToken(); // The annotation token.
}
@@ -1947,6 +1973,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);
+ ConsumeToken(); // The annotation token.
+}
+
/// \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,
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 30e392fa3c94..eaff9fe8eedf 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/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;
@@ -341,6 +341,12 @@ Retry:
ConsumeToken();
return StmtError();
+ case tok::annot_pragma_fp:
+ ProhibitAttributes(Attrs);
+ Diag(Tok, diag::err_pragma_fp_scope);
+ ConsumeToken();
+ return StmtError();
+
case tok::annot_pragma_opencl_extension:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
@@ -900,6 +906,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 +1188,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 +1222,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 +1909,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/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
index 293de78505ef..d6f16bb0cb79 100644
--- a/lib/Parse/ParseStmtAsm.cpp
+++ b/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/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 6a09ea7abca0..d2b18e7c0a81 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/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"
@@ -701,8 +701,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())
@@ -1000,13 +1000,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;
}
@@ -1064,7 +1064,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 +1084,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());
@@ -1267,7 +1275,8 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
bool
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
// Template argument lists are constant-evaluation contexts.
- EnterExpressionEvaluationContext EvalContext(Actions,Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext EvalContext(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ColonProtectionRAIIObject ColonProtection(*this, false);
do {
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 52e5194e6236..aa8ed91d382f 100644
--- a/lib/Parse/Parser.cpp
+++ b/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.
//===----------------------------------------------------------------------===//
@@ -493,6 +488,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;
@@ -688,6 +685,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;
@@ -1701,6 +1701,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
+ TemplateId->Name,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
@@ -1742,7 +1743,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();
@@ -1964,8 +1966,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;
}
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index a987a8ce0b31..50ad113fc880 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -972,7 +972,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 +1003,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 +1169,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(),
diff --git a/lib/Sema/CoroutineStmtBuilder.h b/lib/Sema/CoroutineStmtBuilder.h
new file mode 100644
index 000000000000..4958576219e5
--- /dev/null
+++ b/lib/Sema/CoroutineStmtBuilder.h
@@ -0,0 +1,70 @@
+//===- 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;
+ QualType RetType;
+ 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();
+
+ bool isInvalid() const { return !this->IsValid; }
+
+private:
+ bool makePromiseStmt();
+ bool makeInitialAndFinalSuspend();
+ bool makeNewAndDeleteExpr();
+ bool makeOnFallthrough();
+ bool makeOnException();
+ bool makeReturnObject();
+ bool makeReturnOnAllocFailure();
+ bool makeParamMoves();
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_SEMA_COROUTINESTMTBUILDER_H
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index 077a56ff8e7f..b7e343c64718 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/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/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
index 3970b4136982..b309a36a30a3 100644
--- a/lib/Sema/ScopeInfo.cpp
+++ b/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/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 412f944f89c0..294b56059b33 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -122,8 +122,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 +218,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 +328,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.
@@ -745,7 +745,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) {
@@ -1007,7 +1009,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 +1097,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
@@ -1236,21 +1233,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 +1256,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;
}
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index bad9e7024267..c6e3cc886316 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -215,6 +215,7 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
ValueType Value) {
if (Action == PSK_Reset) {
CurrentValue = DefaultValue;
+ CurrentPragmaLocation = PragmaLocation;
return;
}
if (Action & PSK_Push)
@@ -447,16 +448,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/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp
index 282633bbc9e1..b938ac387c4d 100644
--- a/lib/Sema/SemaCUDA.cpp
+++ b/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 {
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index d8971c0d37eb..57471de78d3e 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/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,15 @@ 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) {
LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
- LookupNestedNameSpecifierName);
+ OnlyNamespace ? LookupNamespaceName
+ : LookupNestedNameSpecifierName);
QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType);
// Determine where to perform name lookup
@@ -594,7 +595,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 +822,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 +934,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/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 6222e4cec47a..7e91709e67da 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/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;
}
@@ -871,8 +871,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 +935,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 +1763,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 +1791,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;
@@ -2273,8 +2272,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 +2540,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();
@@ -2628,11 +2629,12 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
}
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/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 3aedb2a8c9bb..81db0d3d00a7 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/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();
@@ -315,7 +315,7 @@ static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) {
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);
@@ -408,10 +408,10 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
}
// Third argument is always an ndrange_t type.
- if (!Arg2->getType()->isNDRangeT()) {
+ if (Arg2->getType().getAsString() != "ndrange_t") {
S.Diag(TheCall->getArg(2)->getLocStart(),
diag::err_opencl_enqueue_kernel_expected_type)
- << S.Context.OCLNDRangeTy;
+ << "'ndrange_t'";
return true;
}
@@ -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;
@@ -1990,6 +1986,109 @@ 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);
@@ -2001,6 +2100,10 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
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 +2300,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:
@@ -6782,7 +6895,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 +7453,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 +8348,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 +8378,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 +8729,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 +8869,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"
@@ -10609,6 +10775,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 +11486,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 +12011,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;
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 94cfc4baca51..cfac3f1dc1de 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/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,6 +1857,8 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("identifier");
Results.AddResult(Result(Builder.TakeString()));
+
+ AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
}
// Fall through (for statement expressions).
@@ -2253,6 +2288,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
@@ -2585,6 +2629,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:
@@ -3482,6 +3527,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"));
}
@@ -4012,30 +4062,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 +4318,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());
@@ -5230,24 +5307,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 +5348,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 +5358,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);
}
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index 9814b4a84f29..4a55e51495a8 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -11,31 +11,46 @@
//
//===----------------------------------------------------------------------===//
-#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 bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
+ SourceLocation Loc) {
+ DeclarationName DN = S.PP.getIdentifierInfo(Name);
+ LookupResult LR(S, DN, Loc, Sema::LookupMemberName);
+ // Suppress diagnostics when a private member is selected. The same warnings
+ // will be produced again when building the call.
+ LR.suppressDiagnostics();
+ return S.LookupQualifiedName(LR, RD);
+}
+
/// Look up the std::coroutine_traits<...>::promise_type for the given
/// function type.
static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
- SourceLocation Loc) {
+ SourceLocation KwLoc,
+ SourceLocation FuncLoc) {
// 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();
}
@@ -49,56 +64,107 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
}
// Form template argument list for coroutine_traits<R, P1, P2, ...>.
- TemplateArgumentListInfo Args(Loc, Loc);
+ TemplateArgumentListInfo Args(KwLoc, KwLoc);
Args.addArgument(TemplateArgumentLoc(
TemplateArgument(FnType->getReturnType()),
- S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc)));
+ S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), KwLoc)));
// FIXME: If the function is a non-static member function, add the type
// of the implicit object parameter before the formal parameters.
for (QualType T : FnType->getParamTypes())
Args.addArgument(TemplateArgumentLoc(
- TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc)));
+ TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc)));
// 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::coroutine_traits<...>::promise_type for the given
+/// function type.
+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 +226,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 +286,41 @@ 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;
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,18 +337,23 @@ 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();
@@ -268,26 +363,177 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
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();
+
+ // Call 'yield_value', passing in E.
+ 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);
+
+ QualType T =
+ FD->getType()->isDependentType()
+ ? Context.DependentTy
+ : lookupPromiseType(*this, FD->getType()->castAs<FunctionProtoType>(),
+ Loc, FD->getLocation());
+ 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);
+ 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;
+}
+
+static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
+ StringRef Keyword) {
+ if (!checkCoroutineContext(S, KWLoc, Keyword))
+ return false;
+ auto *ScopeInfo = S.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>(S.CurContext);
+ SourceLocation Loc = Fn->getLocation();
+ // Build the initial suspend point
+ auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
+ ExprResult Suspend =
+ buildPromiseCall(S, ScopeInfo->CoroutinePromise, Loc, Name, None);
+ if (Suspend.isInvalid())
+ return StmtError();
+ Suspend = buildOperatorCoawaitCall(S, SC, Loc, Suspend.get());
+ if (Suspend.isInvalid())
+ return StmtError();
+ Suspend = S.BuildResolvedCoawaitExpr(Loc, Suspend.get(),
+ /*IsImplicit*/ true);
+ Suspend = S.ActOnFinishFullExpr(Suspend.get());
+ if (Suspend.isInvalid()) {
+ S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ << ((Name == "initial_suspend") ? 0 : 1);
+ S.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(*this, 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();
- ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
+ 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;
+ }
+
+ 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 +544,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 +555,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(*this, 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 +599,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 +608,29 @@ 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);
+ 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(*this, 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,48 +643,20 @@ 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);
- return Res;
-}
-
-static ExprResult buildStdCurrentExceptionCall(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);
- if (!S.LookupQualifiedName(Result, Std)) {
- S.Diag(Loc, diag::err_implied_std_current_exception_not_found);
- return ExprError();
- }
-
- // 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();
- }
+ Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE, IsImplicit);
return Res;
}
@@ -482,21 +685,170 @@ 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->CoroutinePromise && "not a coroutine");
+
+ if (!Body) {
+ assert(FD->isInvalidDecl() &&
+ "a null body is only allowed for invalid declarations");
+ return;
+ }
+
+ if (isa<CoroutineBodyStmt>(Body)) {
+ // FIXME(EricWF): 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() &&
+ makeReturnOnAllocFailure() && makeNewAndDeleteExpr();
+ return this->IsValid;
+}
+
+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;
+
+ // FIXME: ActOnReturnStmt expects a scope that is inside of the function, due
+ // to CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
+ // S.getCurScope()->getFnParent() == nullptr at ActOnFinishFunctionBody when
+ // CoroutineBodyStmt is built. Figure it out and fix it.
+ // Use BuildReturnStmt here to unbreak sanitized tests. (Gor:3/27/2017)
+ StmtResult ReturnStmt =
+ S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get());
+ if (ReturnStmt.isInvalid())
+ 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.
+ // FIXME: Add nothrow_t placement arg for global alloc
+ // if ReturnStmtOnAllocFailure != nullptr.
// FIXME: Add support for stateful allocators.
FunctionDecl *OperatorNew = nullptr;
@@ -532,8 +884,6 @@ static bool buildAllocationAndDeallocation(Sema &S, SourceLocation Loc,
if (NewExpr.isInvalid())
return false;
- Allocation = NewExpr.get();
-
// Make delete call.
QualType OpDeleteQualType = OperatorDelete->getType();
@@ -559,138 +909,107 @@ static bool buildAllocationAndDeallocation(Sema &S, SourceLocation Loc,
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);
- }
+ // [dcl.fct.def.coroutine]/4
+ // The unqualified-ids 'return_void' and 'return_value' are looked up in
+ // the scope of class P. If both are found, the program is ill-formed.
+ const bool HasRVoid = lookupMember(S, "return_void", PromiseRecordDecl, Loc);
+ const bool HasRValue = lookupMember(S, "return_value", PromiseRecordDecl, Loc);
- SourceLocation Loc = FD->getLocation();
+ StmtResult Fallthrough;
+ if (HasRVoid && HasRValue) {
+ // FIXME Improve this diagnostic
+ S.Diag(FD.getLocation(), diag::err_coroutine_promise_return_ill_formed)
+ << 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 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();
+ this->OnFallthrough = Fallthrough.get();
+ return true;
+}
- // 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();
+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;
+ return !RequireUnhandledException;
+ }
- // 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();
+ // If exceptions are disabled, don't try to build OnException.
+ if (!S.getLangOpts().CXXExceptions)
+ return true;
- // Form and check allocation and deallocation calls.
- Expr *Allocation = nullptr;
- Stmt *Deallocation = nullptr;
- if (!buildAllocationAndDeallocation(*this, Loc, Fn, Allocation, Deallocation))
- return FD->setInvalidDecl();
+ ExprResult UnhandledException = buildPromiseCall(S, Fn.CoroutinePromise, Loc,
+ "unhandled_exception", None);
+ UnhandledException = S.ActOnFinishFullExpr(UnhandledException.get(), Loc);
+ if (UnhandledException.isInvalid())
+ return false;
- // 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();
- }
+ this->OnException = UnhandledException.get();
+ return true;
+}
- // [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();
- }
- }
+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();
+ return false;
+ QualType RetType = FD.getReturnType();
if (!RetType->isDependentType()) {
InitializedEntity Entity =
InitializedEntity::InitializeResult(Loc, RetType, false);
- ReturnObject = PerformMoveOrCopyInitialization(Entity, nullptr, RetType,
+ ReturnObject = S.PerformMoveOrCopyInitialization(Entity, nullptr, RetType,
ReturnObject.get());
if (ReturnObject.isInvalid())
- return FD->setInvalidDecl();
+ return false;
}
- ReturnObject = ActOnFinishFullExpr(ReturnObject.get(), Loc);
+ ReturnObject = S.ActOnFinishFullExpr(ReturnObject.get(), Loc);
if (ReturnObject.isInvalid())
- return FD->setInvalidDecl();
+ return false;
+ this->ReturnValue = ReturnObject.get();
+ return true;
+}
+
+bool CoroutineStmtBuilder::makeParamMoves() {
// FIXME: Perform move-initialization of parameters into frame-local copies.
- SmallVector<Expr*, 16> ParamMoves;
+ return true;
+}
- // 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);
+StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) {
+ CoroutineBodyStmt *Res = CoroutineBodyStmt::Create(Context, Args);
+ if (!Res)
+ return StmtError();
+ return Res;
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index adcf2ee00e75..c6a0b0101d37 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -67,7 +67,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false,
bool AllowTemplates=false)
: AllowInvalidDecl(AllowInvalid), WantClassName(WantClass),
- AllowClassTemplates(AllowTemplates) {
+ AllowTemplates(AllowTemplates) {
WantExpressionKeywords = false;
WantCXXNamedCasts = false;
WantRemainingKeywords = false;
@@ -76,7 +76,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
bool ValidateCandidate(const TypoCorrection &candidate) override {
if (NamedDecl *ND = candidate.getCorrectionDecl()) {
bool IsType = isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
- bool AllowedTemplate = AllowClassTemplates && isa<ClassTemplateDecl>(ND);
+ bool AllowedTemplate = AllowTemplates && getAsTypeTemplateDecl(ND);
return (IsType || AllowedTemplate) &&
(AllowInvalidDecl || !ND->isInvalidDecl());
}
@@ -86,7 +86,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
private:
bool AllowInvalidDecl;
bool WantClassName;
- bool AllowClassTemplates;
+ bool AllowTemplates;
};
} // end anonymous namespace
@@ -252,7 +252,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 +340,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 +366,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)
@@ -391,7 +399,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 +434,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 +464,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);
}
@@ -636,6 +662,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
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,
@@ -656,7 +683,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();
@@ -782,6 +810,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 +1107,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.
@@ -2101,7 +2154,9 @@ 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;
@@ -3035,7 +3090,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;
@@ -4622,6 +4677,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 +5465,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 +5532,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 +5546,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 +5744,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 +5807,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 +5825,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 +6003,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;
}
@@ -6017,7 +6117,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- bool IsExplicitSpecialization = false;
+ bool IsMemberSpecialization = false;
bool IsVariableTemplateSpecialization = false;
bool IsPartialSpecialization = false;
bool IsVariableTemplate = false;
@@ -6029,7 +6129,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 +6195,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 +6265,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) {
@@ -6321,7 +6421,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());
@@ -6436,7 +6536,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 +6551,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 +6666,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) {
@@ -6580,13 +6680,25 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
/// 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 +6713,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 +6764,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 +6776,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))
@@ -6668,7 +6800,8 @@ void Sema::CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl,
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,7 +6815,8 @@ 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;
}
}
@@ -7430,6 +7564,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 +7607,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 +7698,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.
@@ -7835,7 +7977,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 +8033,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 +8048,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 +8192,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 +8382,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).
@@ -8389,7 +8532,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 +8540,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 +8675,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 +8690,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 +8796,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 +8857,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());
}
@@ -8840,15 +8982,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");
@@ -8895,14 +9038,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// 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);
+ NamedDecl *OverloadedDecl =
+ Redeclaration ? OldDecl : Previous.getRepresentativeDecl();
+ Diag(OverloadedDecl->getLocation(),
+ diag::note_attribute_overloadable_prev_overload);
NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
}
}
@@ -8961,7 +9100,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 +9137,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());
@@ -9048,6 +9187,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 +9543,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 +9851,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 +9957,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 +9966,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 +10035,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 +10141,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 +10206,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);
@@ -10111,7 +10271,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 +10441,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 +10456,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 +10837,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 +10889,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
@@ -10865,7 +11010,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)
@@ -11045,6 +11191,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 +11206,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 +11273,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 +11489,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 +11707,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))
@@ -11635,9 +11791,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,6 +11800,18 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
else
FD = cast<FunctionDecl>(D);
+ // 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 (!FD->isLateTemplateParsed()) {
CheckForFunctionRedefinition(FD, nullptr, SkipBody);
@@ -11671,14 +11836,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 +11958,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,7 +12006,7 @@ 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()->CoroutinePromise)
CheckCompletedCoroutineBody(FD, Body);
if (FD) {
@@ -11962,7 +12127,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
!LangOpts.CPlusPlus) {
TypeSourceInfo *TI = FD->getTypeSourceInfo();
TypeLoc TL = TI->getTypeLoc();
- FunctionTypeLoc FTL = TL.castAs<FunctionTypeLoc>();
+ FunctionTypeLoc FTL = TL.getAsAdjusted<FunctionTypeLoc>();
Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 1;
}
}
@@ -12555,7 +12720,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)
@@ -12711,8 +12876,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 +12888,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 +12915,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;
}
}
}
@@ -13070,7 +13235,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 +13255,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,
@@ -13195,7 +13360,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() !=
@@ -13289,7 +13454,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.
@@ -13421,7 +13586,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;
@@ -13452,7 +13617,7 @@ CreateNewDecl:
}
if (ModulePrivateLoc.isValid()) {
- if (isExplicitSpecialization)
+ if (isMemberSpecialization)
Diag(New->getLocation(), diag::err_module_private_specialization)
<< 2
<< FixItHint::CreateRemoval(ModulePrivateLoc);
@@ -13465,7 +13630,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 +13654,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 +13672,9 @@ CreateNewDecl:
if (TUK == TUK_Definition)
New->startDefinition();
+ if (Attr)
+ ProcessDeclAttributeList(S, New, Attr);
+
// 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;
@@ -13632,8 +13797,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 +14506,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 +14641,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 +14661,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 &&
@@ -15207,7 +15373,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 +15618,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.
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index c6a5bc74145c..a1ba9de368db 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/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;
+}
+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) {
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 (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;
@@ -1420,7 +1460,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 +1524,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 +1581,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 +1923,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()));
}
@@ -2409,6 +2504,32 @@ 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");
+
+ if (!isa<NamedDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedNamedDecl;
+ return;
+ }
+
+ 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,
@@ -2917,6 +3038,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 +3336,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 +4192,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())
@@ -4397,6 +4561,19 @@ 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))
+ 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.
//===----------------------------------------------------------------------===//
@@ -5126,6 +5303,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 +5343,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;
@@ -5700,6 +5906,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 +5981,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 +5993,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 +6052,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;
@@ -6056,6 +6274,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;
@@ -6223,6 +6444,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;
}
}
@@ -6282,6 +6506,15 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
}
}
+// Helper for delayed proccessing 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,
@@ -6611,6 +6844,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 = D->getLocation();
// Matches 'diag::note_property_attribute' options.
unsigned property_note_select;
@@ -6633,6 +6867,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 = D->getAttr<DeprecatedAttr>())
+ NoteLocation = attr->getLocation();
break;
case AR_Unavailable:
@@ -6751,7 +6987,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
}
else
- S.Diag(D->getLocation(), diag_available_here)
+ S.Diag(NoteLocation, diag_available_here)
<< D << available_here_select_kind;
if (K == AR_NotYetIntroduced)
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f265f4c00f71..fd3f266c9a08 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/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;
}
@@ -647,6 +647,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 +981,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 +2717,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 +2727,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 +2771,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 +3020,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 +3738,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);
@@ -4332,11 +4400,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 +5080,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 +5092,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 +5118,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
MarkFunctionReferenced(Location, Dtor);
DiagnoseUseOfDecl(Dtor, Location);
}
+
+ if (!VisitVirtualBases)
+ return;
// Virtual bases.
for (const auto &VBase : ClassDecl->vbases()) {
@@ -5378,7 +5453,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()) {
@@ -5786,7 +5861,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 +5984,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 +6100,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 +6371,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 +6409,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 +6519,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 +6549,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 +6628,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 +6648,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 +6710,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 +6718,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 +6889,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 +7011,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 +7030,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 +7146,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();
@@ -8033,6 +8169,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
//===----------------------------------------------------------------------===//
@@ -8397,7 +8681,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 +8897,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 +9456,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()) {
@@ -9816,123 +10106,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 +10224,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 +10273,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(
@@ -10262,45 +10557,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
@@ -10852,7 +11108,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 +11143,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
@@ -11286,59 +11486,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
}
-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 +11596,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 +11633,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.
@@ -11723,52 +11870,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
}
-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:
@@ -11896,65 +11997,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
}
-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());
@@ -12198,7 +12240,7 @@ 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()));
// We're done; notify the mutation listener, if any.
@@ -12750,7 +12792,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 +13118,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
@@ -13245,10 +13288,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 +13356,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 +13377,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;
}
}
@@ -13744,6 +13787,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:
@@ -14157,7 +14203,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
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index b43e5b9e3278..e50f8b206779 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -258,7 +258,8 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S,
S.Diag(ND->getLocation(), diag::note_method_declared_at)
<< ND->getDeclName();
else
- S.Diag(ND->getLocation(), diag::note_previous_decl) << "class";
+ S.Diag(ND->getLocation(), diag::note_previous_decl)
+ << (isa<ObjCCategoryDecl>(ND) ? "category" : "class");
}
}
@@ -1724,7 +1725,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 +1803,9 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
NumProtoRefs, Context);
}
+ if (AttrList)
+ ProcessDeclAttributeList(TUScope, CDecl, AttrList);
+
CheckObjCDeclScope(CDecl);
return ActOnObjCContainerStartDefinition(CDecl);
}
@@ -1865,9 +1870,10 @@ 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->isDeprecated() ? CatIDecl : dyn_cast<NamedDecl>(IDecl),
+ CDecl->getLocation(), 2);
}
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 2ac2aca6f660..deb6cbb53aff 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/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/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0077d6c539c3..bb174521c72c 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -333,10 +333,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;
}
@@ -706,8 +704,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 +1431,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 +1441,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 +1772,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 +1891,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() &&
@@ -2510,11 +2512,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 +3040,9 @@ ExprResult Sema::BuildDeclarationNameExpr(
break;
}
+ case Decl::CXXDeductionGuide:
+ llvm_unreachable("building reference to deduction guide");
+
case Decl::MSProperty:
valueKind = VK_LValue;
break;
@@ -3694,7 +3699,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 +3974,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 +4559,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
@@ -5378,6 +5384,15 @@ 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>())
+ if (!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 +6338,98 @@ 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);
+ } else
+ 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 */;
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 +7399,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 +7645,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 +7662,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 +7701,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 +7908,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 +7985,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;
}
@@ -8094,7 +8147,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &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;
@@ -9231,7 +9284,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 +9427,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 +9616,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 +9714,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 +9781,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 +9799,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 +9816,7 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 &&
vType->hasFloatingRepresentation())
return InvalidOperands(Loc, LHS, RHS);
-
+
return GetSignedVectorType(LHS.get()->getType());
}
@@ -9792,7 +9869,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 +10345,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 +10356,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 +10410,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 +11005,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 +11145,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();
@@ -11212,7 +11294,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 +11302,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
@@ -11659,7 +11741,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());
}
@@ -12193,7 +12275,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,
@@ -13086,7 +13169,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 +13190,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 +13207,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 +13249,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 +13279,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 +13440,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())
@@ -13540,6 +13623,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 +13667,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 +13744,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 +14028,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 +14359,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
@@ -14363,7 +14496,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 +14617,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));
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 3afa95f7d1f2..d65570fcef76 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -323,20 +323,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 +459,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.
@@ -968,7 +979,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 +1117,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 +1228,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 +1256,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 +1339,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 +1531,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 +1584,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,
@@ -1643,8 +1653,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 +1971,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,
@@ -2025,9 +2048,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);
@@ -3094,10 +3118,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()) {
@@ -3703,10 +3728,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 +3753,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;
@@ -4033,6 +4057,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
// C++0x [meta.unary.prop] Table 49 requires the following traits to be
// applied to a complete type.
+ case UTT_IsAggregate:
case UTT_IsTrivial:
case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout:
@@ -4207,6 +4232,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.
@@ -4495,25 +4526,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 +4598,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 +4620,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
@@ -4763,7 +4775,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 +4827,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 +4843,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);
@@ -5967,9 +5980,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 +6161,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 +6427,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 +6478,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 +6600,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 +6630,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 +6660,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 +6682,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 +6750,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 +6802,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/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index c9aa99ee383c..b18de7e94686 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/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;
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 7dbd660f53ec..9cc443ed4fd9 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1984,13 +1984,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 +2011,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 +2266,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 +2515,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 +2557,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 +2750,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 +2994,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 +3011,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 +3061,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 +3100,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 +3355,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 +4108,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 +4151,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
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index b053c83c3f69..d0f530010a0d 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/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");
}
@@ -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;
@@ -8223,3 +8300,219 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
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/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index a0d574915eba..7a9a8ff911aa 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/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
@@ -763,7 +763,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 +1127,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 +1385,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 +1439,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.
@@ -1476,10 +1514,14 @@ 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())
+ DiagnoseUnusedLambdaCapture(From);
+
// Handle 'this' capture.
if (From.isThisCapture()) {
Captures.push_back(
@@ -1564,9 +1606,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 +1618,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 +1649,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/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index e2cb2c8169ce..e4d420f36832 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/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;
@@ -1041,7 +1045,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
@@ -1426,14 +1430,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;
}
@@ -1554,7 +1557,7 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
|| (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus))
? isVisible(SemaRef, cast<NamedDecl>(DC))
: SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) {
- if (SemaRef.ActiveTemplateInstantiations.empty() &&
+ if (SemaRef.CodeSynthesisContexts.empty() &&
// FIXME: Do something better in this case.
!SemaRef.getLangOpts().ModulesLocalVisibility) {
// Cache the fact that this declaration is implicitly visible because
@@ -2694,6 +2697,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 +2818,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 +2848,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 +2868,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 +2951,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 +3016,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 +3033,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 +3075,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 +3091,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 +3109,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 +3434,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;
}
@@ -4498,9 +4508,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'.
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 3481b82679c2..6c5716454874 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/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));
@@ -2177,12 +2185,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/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index dcd19c8d817d..616ab05eaec8 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -1050,7 +1050,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 +1595,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 +1608,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 +1644,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: {
@@ -1737,6 +1758,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 +1823,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 +1882,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 +1896,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 +1926,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 CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
+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,
OpenMPDirectiveKind CurrentRegion,
const DeclarationNameInfo &CurrentName,
OpenMPDirectiveKind CancelRegion,
@@ -2180,7 +2273,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 +2288,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.
@@ -4101,6 +4200,36 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
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.
bool HasErrors = false;
Built.Counters.resize(NestedLoopCount);
@@ -4215,6 +4344,8 @@ 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();
Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get();
// Fill data for doacross depend clauses.
@@ -5748,12 +5879,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 +5895,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();
@@ -6551,6 +6670,322 @@ 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_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 +6993,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 +7003,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 +7112,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 +7121,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,
@@ -10451,7 +10908,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 +10963,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 +11025,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 +11034,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 +11051,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 +11060,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/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index f976b76727f5..29ba34479dab 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -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,
@@ -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) {
@@ -4048,7 +4047,7 @@ 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'
// type is better than a conversion to 'id'.
if (ToPtr1->isObjCIdType() &&
@@ -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) &&
@@ -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,
@@ -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 =
@@ -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
@@ -6760,7 +6791,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
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;
@@ -7109,7 +7142,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
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());
@@ -8991,6 +9025,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 &&
@@ -9488,7 +9528,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;
@@ -11485,7 +11526,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 +11998,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.
@@ -12027,7 +12068,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();
@@ -12125,12 +12166,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?
@@ -12144,7 +12185,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
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.
@@ -12259,7 +12300,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))
@@ -12407,7 +12448,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.
@@ -12483,7 +12524,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();
@@ -13046,7 +13087,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;
@@ -13226,7 +13267,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();
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 8e53fda846f4..b6b429d1f25c 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/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() {
@@ -1587,7 +1586,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 +1652,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/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 390e1b52c8ed..9be1c56f0622 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/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)
@@ -1810,7 +1821,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)
@@ -2866,7 +2877,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 +3170,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 +3227,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);
@@ -3914,7 +3928,8 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
else
CurContext = CD;
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
@@ -3966,7 +3981,8 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
else
CurContext = CD;
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::ActOnCapturedRegionError() {
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 76de9e299399..5f91cac14a38 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -623,8 +623,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/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 01fa856132d7..4ee3412170a8 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/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/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ad1e89a0ca64..f522e76b0673 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/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,
@@ -1137,6 +1188,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 +1202,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,
@@ -1250,10 +1327,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 +1415,368 @@ 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 =
+ Args.getNumLevels()
+ ? SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),
+ OldParam->getDeclName())
+ : OldDI;
+ 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 +2109,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 +2119,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 +2254,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 +2268,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 +2379,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
Diag(DeclLoc, diag::err_specialize_member_of_template)
<< !Recovery << Range;
Invalid = true;
- IsExplicitSpecialization = false;
+ IsMemberSpecialization = false;
return true;
}
@@ -1996,7 +2449,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (Record->getTemplateSpecializationKind()
!= TSK_ExplicitSpecialization &&
TypeIdx == NumTypes - 1)
- IsExplicitSpecialization = true;
+ IsMemberSpecialization = true;
continue;
}
@@ -2030,9 +2483,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 +2558,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));
@@ -2402,6 +2854,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 +2880,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 +2944,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 +2952,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 +2961,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 +3185,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 +3229,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 +3243,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 +3747,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 +3796,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 +3868,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);
@@ -3520,8 +4062,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 +4199,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 +4438,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 +4497,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 +4562,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 +4605,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 +4804,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 +4945,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());
}
@@ -5093,6 +5681,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 +5761,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 +5818,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 +6349,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 +6440,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 +6496,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 +6799,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 +7073,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 +7084,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 +7134,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");
}
@@ -8087,6 +8679,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
@@ -8491,7 +9091,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 +9103,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 +9137,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 +9145,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 +9154,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)
@@ -8667,14 +9281,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;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 93e796ee9668..ebdf6dd57fc5 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -112,6 +112,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 +343,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 +638,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 +708,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 +732,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 +744,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 +787,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 +841,7 @@ private:
SmallVectorImpl<DeducedTemplateArgument> &Deduced;
TemplateDeductionInfo &Info;
unsigned PackElements = 0;
+ bool IsPartiallyExpanded = false;
SmallVector<DeducedPack, 2> Packs;
};
@@ -963,6 +1026,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 +1172,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();
}
}
@@ -1723,6 +1806,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:
@@ -2335,7 +2419,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 +2447,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 +2520,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 +2577,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 +2620,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 +2653,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 +2701,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 +2716,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;
@@ -2920,16 +3000,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 +3266,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 +3299,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 +3361,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 +3400,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 +3414,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 +3431,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 +3441,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 +3498,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 +3554,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);
};
@@ -3659,7 +3737,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
Deduced.resize(TemplateParams->size());
@@ -3907,7 +3986,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 +4100,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 +4129,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 +4202,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 +4225,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 +4250,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 +4265,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 +4284,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 +4296,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 +4313,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 +4336,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 +4952,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
@@ -5154,8 +5251,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/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 9f744a1dc1b2..edd6edfce9dc 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/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,19 @@ bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
return true;
case DefaultTemplateArgumentChecking:
+ case DeclaringSpecialMember:
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 +219,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 +228,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 +241,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 +257,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation,
+ CodeSynthesisContext::DefaultTemplateArgumentInstantiation,
PointOfInstantiation, InstantiationRange, getAsNamedDecl(Param),
Template, TemplateArgs) {}
@@ -267,14 +265,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 +282,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, Template, nullptr,
TemplateArgs, &DeductionInfo) {}
@@ -295,7 +293,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, PartialSpec, nullptr,
TemplateArgs, &DeductionInfo) {}
@@ -306,7 +304,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, PartialSpec, nullptr,
TemplateArgs, &DeductionInfo) {}
@@ -315,7 +313,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation,
+ CodeSynthesisContext::DefaultFunctionArgumentInstantiation,
PointOfInstantiation, InstantiationRange, Param, nullptr,
TemplateArgs) {}
@@ -325,7 +323,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
+ CodeSynthesisContext::PriorTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
@@ -335,7 +333,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
+ CodeSynthesisContext::PriorTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
@@ -344,36 +342,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 +403,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 +422,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 +442,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 +490,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 +504,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 +516,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 +554,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 +570,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 +594,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 +612,18 @@ 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;
}
}
}
@@ -605,39 +632,49 @@ 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:
+ // 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 +843,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 +1078,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 +1132,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 +1158,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 +1483,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 +1541,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 +1560,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 +1598,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 +1643,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");
@@ -1758,7 +1815,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 +1939,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 +2002,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
@@ -2173,8 +2233,8 @@ bool Sema::InstantiateEnum(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);
LocalInstantiationScope Scope(*this, /*MergeWithParentScope*/true);
@@ -2245,8 +2305,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);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 200775756d3a..9a71a17561c7 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/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);
}
@@ -1600,13 +1649,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 +1710,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 +1720,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);
}
@@ -2075,13 +2124,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 +2265,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 +2393,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 +2822,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 +3599,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 +3613,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
@@ -3810,8 +3856,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// 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 +3910,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);
@@ -4073,9 +4121,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;
@@ -4954,6 +5004,28 @@ 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;
+ DC = T->getAsCXXRecordDecl();
+ continue;
+ }
}
DC = DC->getParent();
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 725a3e425201..9f572007d8a7 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/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/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 2cdf76caa7ef..279b9ecef94e 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -742,7 +742,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 +1502,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:
@@ -2766,6 +2733,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 +2751,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 +2772,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 +2814,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 +2823,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 +2839,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 +2858,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 +2879,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 +2889,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 +2901,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 +2962,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:
@@ -3623,17 +3644,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)
@@ -3834,6 +3870,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,7 +3959,7 @@ 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 (S.CodeSynthesisContexts.empty()) {
if (T->canHaveNullability() && !T->getNullability(S.Context)) {
if (isVaList(T)) {
// Record that we've seen a pointer, but do nothing else.
@@ -4123,7 +4160,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 +4172,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 +4204,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
@@ -4442,6 +4488,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
HasAnyInterestingExtParameterInfos = true;
}
+ if (Param->hasAttr<PassObjectSizeAttr>()) {
+ ExtParameterInfos[i] = ExtParameterInfos[i].withHasPassObjectSize();
+ HasAnyInterestingExtParameterInfos = true;
+ }
+
ParamTys.push_back(ParamTy);
}
@@ -4574,14 +4625,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 +4656,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 +4684,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 +4768,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:
@@ -5473,14 +5529,14 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
addrSpace.setIsSigned(false);
}
llvm::APSInt max(addrSpace.getBitWidth());
- max = Qualifiers::MaxAddressSpace;
+ max = Qualifiers::MaxAddressSpace - LangAS::Count;
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::Count;
} else {
// The keyword-based type attributes imply which address space to use.
switch (Attr.getKind()) {
@@ -6893,8 +6949,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 &&
@@ -7510,7 +7568,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/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index f8e65a119c3c..693b5c088acc 100644
--- a/lib/Sema/TreeTransform.h
+++ b/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.
@@ -3146,6 +3213,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 +3634,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 +3686,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 +3724,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 +3868,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 +4123,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 +4184,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 +4294,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 +4310,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 +4575,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 +4622,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 +4669,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 +4719,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 +5187,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 +5355,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 +5414,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 +5491,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 +5991,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 +6011,8 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
TL.getElaboratedKeywordLoc(),
QualifierLoc,
T->getIdentifier(),
- TL.getNameLoc());
+ TL.getNameLoc(),
+ DeducedTSTContext);
if (Result.isNull())
return QualType();
@@ -5879,12 +6066,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 +6391,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 +6852,99 @@ 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();
+ }
+
+ return getDerived().RebuildCoroutineBodyStmt(Builder);
}
template<typename Derived>
@@ -6682,7 +6957,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 +6971,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 +7537,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);
@@ -8642,8 +8944,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 +9158,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 +9638,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 +9738,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 +9782,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 +9819,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 +9930,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 +10434,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 +10456,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 +10644,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 +10693,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 +10770,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 +10911,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 +10944,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 +11148,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 +11182,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 +12332,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 +12342,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
SS, TemplateKWLoc, TemplateName,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
- Template);
+ Template, AllowInjectedClassName);
return Template.get();
}
@@ -12036,7 +12351,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 +12363,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
SS, TemplateKWLoc, Name,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
- Template);
+ Template, AllowInjectedClassName);
return Template.get();
}
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index ecd249cc5025..684ec243035e 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/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/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 53224e2b493d..406c4b50d92b 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/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"
@@ -461,19 +464,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 +474,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
@@ -943,6 +956,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 +976,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 +1020,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 +1036,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,7 +1119,7 @@ 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() &&
!PP.getHeaderSearchInfo().getModuleCachePath().empty()) {
@@ -1113,7 +1129,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 +1294,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);
@@ -1575,7 +1596,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()
@@ -1707,15 +1732,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 +1762,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;
@@ -2149,7 +2174,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 +2216,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 +2256,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 +2285,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 +2361,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 +2438,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 +2457,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 +2512,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 +2558,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.InputFileOffsets =
(const llvm::support::unaligned_uint64_t *)Blob.data();
F.InputFilesLoaded.resize(NumInputs);
+ F.NumUserInputFiles = NumUserInputs;
break;
}
}
@@ -2601,7 +2647,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;
@@ -2766,6 +2813,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)
@@ -2916,80 +2971,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))
@@ -3123,14 +3107,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 +3221,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,10 +3298,113 @@ 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;
+ }
+}
+
ASTReader::ASTReadResult
ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
const ModuleFile *ImportedBy,
@@ -3342,8 +3424,7 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
// 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);
@@ -3621,10 +3702,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
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 +3716,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
for (const ImportedModule &IM : Loaded)
LoadedSet.insert(IM.Mod);
- ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
- LoadedSet,
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet,
Context.getLangOpts().Modules
- ? &PP.getHeaderSearchInfo().getModuleMap()
- : nullptr);
+ ? &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.
@@ -3986,6 +4066,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 +4084,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,
@@ -4214,23 +4416,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 +4552,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 +4581,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 +4702,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 +4741,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,
@@ -4628,8 +4841,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()
@@ -4696,13 +4910,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;
@@ -5288,48 +5498,128 @@ 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++];
+ unsigned SeverityAndUpgradedFromWarning = Record[Idx++];
+ bool WasUpgradedFromWarning =
+ DiagnosticMapping::deserializeUpgradedFromWarning(
+ SeverityAndUpgradedFromWarning);
+ DiagnosticMapping NewMapping =
+ Diag.makeUserMapping(DiagnosticMapping::deserializeSeverity(
+ SeverityAndUpgradedFromWarning),
+ Loc);
+ 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 (WasUpgradedFromWarning && !Mapping.isErrorOrFatal()) {
+ Mapping = Diag.makeUserMapping(diag::Severity::Warning, Loc);
+ continue;
}
- diag::Severity Map = (diag::Severity)F.PragmaDiagMappings[Idx++];
- DiagnosticMapping Mapping = Diag.makeUserMapping(Map, Loc);
- Diag.GetCurDiagState()->setMapping(DiagID, Mapping);
+
+ // Use the deserialized mapping verbatim.
+ Mapping = NewMapping;
+ Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
+ }
+ 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[0] == 0 &&
+ "Invalid data, unexpected backref in initial state");
+ Idx = 2 + Record[1] * 2;
+ assert(Idx < Record.size() &&
+ "Invalid data, not enough state change pairs in initial state");
+ } else {
+ FirstState = ReadDiagState(
+ F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.CurDiagState,
+ SourceLocation(), F.isModule());
+ }
+
+ // 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();
}
}
@@ -5606,6 +5896,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 +6138,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 +6346,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());
}
@@ -6304,9 +6618,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 +6674,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 +6751,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
@@ -6543,6 +6851,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");
@@ -6728,6 +7039,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 +7234,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 +7351,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 +7381,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 +7418,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 +7459,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) {
@@ -7720,6 +8034,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 +8075,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 +8090,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()
@@ -7833,7 +8156,8 @@ ASTReader::getSourceDescriptor(unsigned ID) {
// If there is only a single PCH, return it instead.
// Chained PCH are not suported.
- if (ModuleMgr.size() == 1) {
+ 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 +8167,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 +8217,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()
@@ -7915,6 +8249,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 +8300,7 @@ void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
break;
}
}
@@ -8406,11 +8745,11 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
return CXXTemporary::Create(Context, 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);
}
@@ -8493,6 +8832,21 @@ 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);
+ }
+}
+
std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
// If we know the owning module, use it.
if (Module *M = D->getImportedOwningModule())
@@ -8651,9 +9005,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 +9143,504 @@ 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
+ enum {
+ EndOfClass,
+ PublicSpecifer,
+ PrivateSpecifer,
+ ProtectedSpecifer,
+ StaticAssert,
+ Field,
+ CXXMethod,
+ 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:
+ return CXXMethod;
+ }
+ };
+
+ 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;
}
- Diag(RD->getLocation(),
+ FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first;
+ SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first;
+
+ 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;
+
+ Diag(SecondRecord->getLocation(),
diag::note_module_odr_violation_different_definitions)
- << getOwningModuleNameForDiagnostic(RD);
+ << SecondModule;
+ 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,
+ };
+
+ // 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 ComputeDeclNameODRHash = [&Hash](const DeclarationName Name) {
+ Hash.clear();
+ Hash.AddDeclarationName(Name);
+ 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(
+ Context.hasSameType(FirstField->getType(), SecondField->getType()));
+
+ QualType FirstType = FirstField->getType();
+ QualType SecondType = SecondField->getType();
+ const TypedefType *FirstTypedef = dyn_cast<TypedefType>(FirstType);
+ const TypedefType *SecondTypedef = dyn_cast<TypedefType>(SecondType);
+
+ if ((FirstTypedef && !SecondTypedef) ||
+ (!FirstTypedef && SecondTypedef)) {
+ ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
+ FieldTypeName)
+ << FirstII << FirstType;
+ ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
+ FieldTypeName)
+ << SecondII << SecondType;
+
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstTypedef && SecondTypedef) {
+ unsigned FirstHash = ComputeDeclNameODRHash(
+ FirstTypedef->getDecl()->getDeclName());
+ unsigned SecondHash = ComputeDeclNameODRHash(
+ SecondTypedef->getDecl()->getDeclName());
+ if (FirstHash != SecondHash) {
+ 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: {
+ const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl);
+ const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl);
+ auto FirstName = FirstMethod->getDeclName();
+ auto SecondName = SecondMethod->getDeclName();
+ if (FirstName != SecondName) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodName)
+ << FirstName;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodName)
+ << SecondName;
+
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstDeleted = FirstMethod->isDeleted();
+ const bool SecondDeleted = SecondMethod->isDeleted();
+ if (FirstDeleted != SecondDeleted) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodDeleted)
+ << FirstName << FirstDeleted;
+
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodDeleted)
+ << 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)
+ << FirstName << FirstPure << FirstVirtual;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodVirtual)
+ << 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)
+ << FirstName << FirstStatic;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodStatic)
+ << SecondName << SecondStatic;
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstVolatile = FirstMethod->isVolatile();
+ const bool SecondVolatile = SecondMethod->isVolatile();
+ if (FirstVolatile != SecondVolatile) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodVolatile)
+ << FirstName << FirstVolatile;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodVolatile)
+ << SecondName << SecondVolatile;
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstConst = FirstMethod->isConst();
+ const bool SecondConst = SecondMethod->isConst();
+ if (FirstConst != SecondConst) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodConst)
+ << FirstName << FirstConst;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodConst)
+ << SecondName << SecondConst;
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstInline = FirstMethod->isInlineSpecified();
+ const bool SecondInline = SecondMethod->isInlineSpecified();
+ if (FirstInline != SecondInline) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodInline)
+ << FirstName << FirstInline;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodInline)
+ << SecondName << SecondInline;
+ Diagnosed = true;
+ break;
+ }
+
+ break;
+ }
+ }
+
+ if (Diagnosed == true)
+ continue;
+
+ Diag(FirstRecord->getLocation(),
+ diag::err_module_odr_violation_different_definitions)
+ << FirstRecord << FirstModule.empty() << FirstModule;
+
+ Diag(SecondRecord->getLocation(),
+ diag::note_module_odr_violation_different_definitions)
+ << SecondModule;
+ Diagnosed = true;
}
if (!Diagnosed) {
@@ -8905,8 +9739,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),
+ Context(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/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 707a9249dd96..e0304d22fe50 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -119,7 +119,8 @@ 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);
@@ -240,6 +241,7 @@ 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);
@@ -292,6 +294,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 +424,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 +473,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);
}
}
@@ -592,6 +601,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 +752,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();
@@ -1112,8 +1127,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 +1145,6 @@ void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
VisitObjCImplDecl(D);
- D->setIdentifier(Record.getIdentifierInfo());
D->CategoryNameLoc = ReadSourceLocation();
}
@@ -1473,7 +1491,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();
@@ -1512,10 +1530,19 @@ void ASTDeclReader::ReadCXXDefinitionData(
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)
@@ -1641,7 +1668,8 @@ void ASTDeclReader::MergeDefinitionData(
// 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 +1697,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 +1718,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 +1807,10 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
return Redecl;
}
+void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+ VisitFunctionDecl(D);
+}
+
void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
VisitFunctionDecl(D);
@@ -1804,8 +1840,6 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
}
VisitCXXMethodDecl(D);
-
- D->IsExplicitSpecified = Record.readInt();
}
void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
@@ -1821,7 +1855,6 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
VisitCXXMethodDecl(D);
- D->IsExplicitSpecified = Record.readInt();
}
void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
@@ -1831,7 +1864,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 +1906,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;
@@ -2471,12 +2505,11 @@ 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();
#include "clang/Serialization/AttrPCHRead.inc"
@@ -2531,7 +2564,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 +2685,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 +2779,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.
@@ -3323,6 +3415,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;
@@ -3531,12 +3626,37 @@ 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::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(Context, D.getDecl(), D.hasPendingBody()))
+ PassInterestingDeclToConsumer(D.getDecl());
+ }
+}
+
void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
// 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
@@ -3547,6 +3667,9 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
auto UpdateOffsets = std::move(UpdI->second);
DeclUpdateOffsets.erase(UpdI);
+ // FIXME: This call to isConsumerInterestedIn is not safe because
+ // we could be deserializing declarations at the moment. We should
+ // delay calling this in the same way as done in D30793.
bool WasInteresting = isConsumerInterestedIn(Context, D, false);
for (auto &FileAndOffset : UpdateOffsets) {
ModuleFile *F = FileAndOffset.first;
@@ -3568,7 +3691,8 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
// we need to hand it off to the consumer.
if (!WasInteresting &&
isConsumerInterestedIn(Context, D, Reader.hasPendingBody())) {
- InterestingDecls.push_back(D);
+ PotentiallyInterestingDecls.push_back(
+ InterestingDecl(D, Reader.hasPendingBody()));
WasInteresting = true;
}
}
@@ -3858,14 +3982,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;
}
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 686a69bbbcd2..a12fb8cf95a0 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -381,6 +381,11 @@ void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) {
llvm_unreachable("unimplemented");
}
+void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) {
// FIXME: Implement coroutine serialization.
llvm_unreachable("unimplemented");
@@ -665,7 +670,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 +1225,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) {
@@ -1928,7 +1933,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 +1943,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 +1957,7 @@ void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) {
}
void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setNumThreads(Reader->Record.readSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation());
}
@@ -2297,11 +2305,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 +2576,8 @@ 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());
}
SmallVector<Expr *, 4> Sub;
unsigned CollapsedNum = D->getCollapsedNumber();
@@ -2909,7 +2921,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
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 886523ea9431..bb869077f4cd 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/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>
@@ -348,6 +351,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 +426,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 +696,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());
}
@@ -1001,7 +1020,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 +1032,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 +1046,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 +1067,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);
@@ -1242,6 +1259,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 +1326,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;
@@ -1346,15 +1420,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
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);
- }
// Module name
auto Abbrev = std::make_shared<BitCodeAbbrev>();
@@ -1420,17 +1485,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 +1563,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 =
@@ -1623,7 +1676,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
PP.getHeaderSearchInfo().getHeaderSearchOpts(),
PP.getLangOpts().Modules);
Stream.ExitBlock();
- return Signature;
}
namespace {
@@ -1986,6 +2038,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 +2170,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.
@@ -2516,7 +2580,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++;
@@ -2650,11 +2715,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);
}
@@ -2789,43 +2860,68 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
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 AddDiagState = [&](const DiagnosticsEngine::DiagState *State,
+ bool IncludeNonPragmaStates) {
+ 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.serializeBits());
}
}
- 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 +3655,7 @@ public:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXLiteralOperatorName:
+ case DeclarationName::CXXDeductionGuideName:
KeyLen += 4;
break;
case DeclarationName::CXXOperatorName:
@@ -3588,6 +3685,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 +4029,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 +4184,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 +4340,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 +4364,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 +4391,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 +4409,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 +4559,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 +4699,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 +4720,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 +4776,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 +4787,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 +4893,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
WriteMSStructPragmaOptions(SemaRef);
WriteMSPointersToMembersPragmaOptions(SemaRef);
}
+ WritePackPragmaOptions(SemaRef);
// Some simple statistics
RecordData::value_type Record[] = {
@@ -4776,7 +4905,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) {
@@ -5229,6 +5358,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 +5423,7 @@ void ASTRecordWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc,
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
break;
}
}
@@ -5651,10 +5785,20 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
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/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index d8466e9cbf3b..812cd9e916d9 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/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);
@@ -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;
}
@@ -1268,8 +1277,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 +1292,6 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
VisitCXXMethodDecl(D);
- Record.push_back(D->IsExplicitSpecified);
Code = serialization::DECL_CXX_CONVERSION;
}
@@ -2023,6 +2029,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 +2228,11 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
Writer->ClearSwitchCaseIDs();
assert(FD->doesThisDeclarationHaveABody());
+ bool ModulesCodegen = Writer->Context->getLangOpts().ModulesCodegen &&
+ Writer->WritingModule && !FD->isDependentContext();
+ 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/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 01fd98ceadb2..1a2edac65886 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -315,6 +315,11 @@ void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) {
llvm_unreachable("unimplemented");
}
+void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) {
+ // FIXME: Implement coroutine serialization.
+ llvm_unreachable("unimplemented");
+}
+
void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) {
// FIXME: Implement coroutine serialization.
llvm_unreachable("unimplemented");
@@ -645,7 +650,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 +1218,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 +1799,7 @@ void OMPClauseWriter::writeClause(OMPClause *C) {
}
void OMPClauseWriter::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) {
+ Record.push_back(C->getCaptureRegion());
Record.AddStmt(C->getPreInitStmt());
}
@@ -1803,6 +1809,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 +1823,7 @@ void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) {
}
void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getNumThreads());
Record.AddSourceLocation(C->getLParenLoc());
}
@@ -2064,11 +2072,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 +2246,8 @@ 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());
}
for (auto I : D->counters()) {
Record.AddStmt(I);
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 7f1b75055b45..2e0076521f9c 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/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/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
index ae5796ede126..6978e7e09774 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/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/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 72b08610bb4d..5a44d26fe399 100644
--- a/lib/Serialization/Module.cpp
+++ b/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/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index 722b547e803e..1dee4d069861 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
index e6592a285e47..90d5c0e36a47 100644
--- a/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 082a4873217b..d19630eeef77 100644
--- a/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 05505ec38600..60d60bc074eb 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -48,6 +48,7 @@ add_clang_library(clangStaticAnalyzerCheckers
MallocChecker.cpp
MallocOverflowSecurityChecker.cpp
MallocSizeofChecker.cpp
+ MisusedMovedObjectChecker.cpp
MPI-Checker/MPIBugReporter.cpp
MPI-Checker/MPIChecker.cpp
MPI-Checker/MPIFunctionClassifier.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 238032c895f6..32e3ce9270aa 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/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 &,
@@ -1943,8 +1944,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.
@@ -2116,6 +2121,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/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index 3db19946a300..391b843ff3db 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp
index 7631322d255b..668e772fe1b3 100644
--- a/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index f474857a1bf4..07285d27ed9e 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 16a475ae9dd2..65e81315f095 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
index 86764c939dcd..95b6c4d3775d 100644
--- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
index 6fa5732d10cb..1885b0e39203 100644
--- a/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
+++ b/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,30 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
bool ReportNormalClones = Mgr.getAnalyzerOptions().getBooleanOption(
"ReportNormalClones", true, 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, 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;
- if (ReportNormalClones)
- reportClones(BR, Mgr, MinComplexity);
+ // 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));
+
+ reportClones(BR, Mgr, AllCloneGroups);
}
static PathDiagnosticLocation makeLocation(const StmtSequence &S,
@@ -87,37 +107,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 +166,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/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
index 2bb9e858731c..ea894c81011c 100644
--- a/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 2d5cb60edf7d..32040e71163d 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index 8c8acc637f1f..b1a54e77951b 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -65,6 +65,18 @@ private:
/// and thus, is tainted.
static bool isStdin(const Expr *E, CheckerContext &C);
+ /// This is called from getPointedToSymbol() to resolve symbol references for
+ /// the region underlying a LazyCompoundVal. This is the default binding
+ /// for the LCV, which could be a conjured symbol from a function call that
+ /// initialized the region. It only returns the conjured symbol if the LCV
+ /// covers the entire region, e.g. we avoid false positives by not returning
+ /// a default bindingc for an entire struct if the symbol for only a single
+ /// field or element within it is requested.
+ // TODO: Return an appropriate symbol for sub-fields/elements of an LCV so
+ // that they are also appropriately tainted.
+ static SymbolRef getLCVSymbol(CheckerContext &C,
+ nonloc::LazyCompoundVal &LCV);
+
/// \brief Given a pointer argument, get the symbol of the value it contains
/// (points to).
static SymbolRef getPointedToSymbol(CheckerContext &C, const Expr *Arg);
@@ -101,6 +113,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;
@@ -194,6 +222,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,
@@ -423,6 +473,27 @@ bool GenericTaintChecker::checkPre(const CallExpr *CE, CheckerContext &C) const{
return false;
}
+SymbolRef GenericTaintChecker::getLCVSymbol(CheckerContext &C,
+ nonloc::LazyCompoundVal &LCV) {
+ StoreManager &StoreMgr = C.getStoreManager();
+
+ // getLCVSymbol() is reached in a PostStmt so we can always expect a default
+ // binding to exist if one is present.
+ if (Optional<SVal> binding = StoreMgr.getDefaultBinding(LCV)) {
+ SymbolRef Sym = binding->getAsSymbol();
+ if (!Sym)
+ return nullptr;
+
+ // If the LCV covers an entire base region return the default conjured symbol.
+ if (LCV.getRegion() == LCV.getRegion()->getBaseRegion())
+ return Sym;
+ }
+
+ // Otherwise, return a nullptr as there's not yet a functional way to taint
+ // sub-regions of LCVs.
+ return nullptr;
+}
+
SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
const Expr* Arg) {
ProgramStateRef State = C.getState();
@@ -438,6 +509,10 @@ SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr());
SVal Val = State->getSVal(*AddrLoc,
ArgTy ? ArgTy->getPointeeType(): QualType());
+
+ if (auto LCV = Val.getAs<nonloc::LazyCompoundVal>())
+ return getLCVSymbol(C, *LCV);
+
return Val.getAsSymbol();
}
@@ -635,8 +710,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()))
+ const SymbolRef PointedToSym = getPointedToSymbol(C, E);
+ SVal TaintedSVal;
+ if (State->isTainted(PointedToSym))
+ TaintedSVal = nonloc::SymbolVal(PointedToSym);
+ else if (State->isTainted(E, C.getLocationContext()))
+ TaintedSVal = C.getSVal(E);
+ else
return false;
// Generate diagnostic.
@@ -644,6 +724,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/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
index 531054aa7887..f0f7c98c9640 100644
--- a/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
@@ -415,8 +415,6 @@ bool IteratorPastEndChecker::evalCall(const CallExpr *CE,
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) {
diff --git a/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
index c667b9e67d4b..696cf39473d5 100644
--- a/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index f1aa16391db1..f8473dbd7647 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 8e839a1d28fd..6e9b7fefa3d0 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -174,7 +174,10 @@ 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) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -236,7 +239,9 @@ 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;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -554,6 +559,16 @@ 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");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
@@ -589,7 +604,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 +613,11 @@ 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)
return true;
}
@@ -762,7 +782,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,7 +811,8 @@ 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) {
+ } else if (FunI == II_realloc || FunI == II_g_realloc ||
+ FunI == II_g_try_realloc) {
State = ReallocMem(C, CE, false, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_reallocf) {
@@ -801,7 +822,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
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 +862,18 @@ 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);
}
}
@@ -1154,7 +1187,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 =
diff --git a/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp b/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
new file mode 100644
index 000000000000..decc552e1213
--- /dev/null
+++ b/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/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index 1f82ab94af82..6d05159e51b0 100644
--- a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index c14a87c9d2a4..21527d8c347a 100644
--- a/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/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.
diff --git a/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
index b9857e51f3ea..dfd2c9afe7fb 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index eb101e12af25..3f6ae6222ce0 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -2661,6 +2661,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;
@@ -3647,7 +3648,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 +3715,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/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 38d2aa6d8f9d..f3c2ffc58662 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/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/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
index 0b7a4865ddc2..d12ba6258073 100644
--- a/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
+++ b/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;
@@ -252,7 +278,7 @@ void ValistChecker::reportLeakedVALists(const RegionVector &LeakedVALists,
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 +304,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 +322,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 +351,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/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 15422633ba33..45ef612ee1d5 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -230,7 +230,7 @@ bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
return getBooleanOption(SuppressFromCXXStandardLibrary,
"suppress-c++-stdlib",
- /* Default = */ false);
+ /* Default = */ true);
}
bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() {
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index c3c3f2ff76ec..7309741d22e3 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1027,7 +1027,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 +1290,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 +1659,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 +1690,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/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index aaffb0b82ce0..85878f5e96ee 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -1,5 +1,12 @@
set(LLVM_LINK_COMPONENTS support)
+# Link Z3 if the user wants to build it.
+if(CLANG_ANALYZER_WITH_Z3)
+ set(Z3_LINK_FILES ${Z3_LIBRARIES})
+else()
+ set(Z3_LINK_FILES "")
+endif()
+
add_clang_library(clangStaticAnalyzerCore
APSIntType.cpp
AnalysisManager.cpp
@@ -34,6 +41,7 @@ add_clang_library(clangStaticAnalyzerCore
PlistDiagnostics.cpp
ProgramState.cpp
RangeConstraintManager.cpp
+ RangedConstraintManager.cpp
RegionStore.cpp
SValBuilder.cpp
SVals.cpp
@@ -42,6 +50,7 @@ add_clang_library(clangStaticAnalyzerCore
Store.cpp
SubEngine.cpp
SymbolManager.cpp
+ Z3ConstraintManager.cpp
LINK_LIBS
clangAST
@@ -49,4 +58,12 @@ add_clang_library(clangStaticAnalyzerCore
clangBasic
clangLex
clangRewrite
+ ${Z3_LINK_FILES}
)
+
+if(CLANG_ANALYZER_WITH_Z3)
+ target_include_directories(clangStaticAnalyzerCore SYSTEM
+ PRIVATE
+ ${Z3_INCLUDE_DIR}
+ )
+endif()
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 420e2a6b5c8c..ee761689f479 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/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);
@@ -921,7 +959,7 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver);
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 +967,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/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 79e204cdafec..49f3edef2a2d 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/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/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/lib/StaticAnalyzer/Core/ConstraintManager.cpp
index b7db8333aaac..8de2b0e8d271 100644
--- a/lib/StaticAnalyzer/Core/ConstraintManager.cpp
+++ b/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/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp b/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
index fd35b664a912..a01ff36a8aae 100644
--- a/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
+++ b/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/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index d563f8e9eac0..9e6ec09010e9 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/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,
@@ -613,7 +651,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 +813,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 +836,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 +890,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:
@@ -2165,7 +2213,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 +2231,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 +2328,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 +2338,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 +2570,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/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 89fab1d56af0..8f720a2067b1 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/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;
@@ -1053,7 +1054,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/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 7e9b2033ca37..03e0095d0e83 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/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/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 92c5fe6b6f1a..f5e64f4a5a8c 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/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/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index d6e8fe5b51b3..7bc186d5b994 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/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/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 03ace35965cb..31556c792fc5 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/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 =
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 15073bb82b36..e0ad2d8ad45c 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/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/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
new file mode 100644
index 000000000000..1304116f4974
--- /dev/null
+++ b/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/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/RangedConstraintManager.h
index 1128e775b320..a4e6062a4f57 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/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/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 934cc5cd3ac4..dd7e9dd11781 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -494,6 +494,11 @@ 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);
+ return B.getDefaultBinding(R);
+ }
+
SVal getBinding(RegionBindingsConstRef B, Loc L, QualType T = QualType());
SVal getBindingForElement(RegionBindingsConstRef B, const ElementRegion *R);
@@ -1336,7 +1341,8 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array, QualType T) {
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 +1385,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/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 0e512ff80861..adb40178f5b1 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/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/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 28b43dd566d5..82ce8b45fe78 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/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);
};
@@ -362,6 +367,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 +542,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 +950,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 +999,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/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index aca6e3b6255b..ba48a60d5a1c 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/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:
@@ -434,7 +435,8 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
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 +473,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 +485,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/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp b/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp
new file mode 100644
index 000000000000..f9f9057a89cd
--- /dev/null
+++ b/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/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index b3e287ebf815..0fe0f3a6ed58 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/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()) {
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
index 2eec1dba2f36..7b0c58e7947d 100644
--- a/lib/Tooling/CMakeLists.txt
+++ b/lib/Tooling/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
)
add_subdirectory(Core)
+add_subdirectory(Refactoring)
add_clang_library(clangTooling
ArgumentsAdjusters.cpp
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index 308c1ac48b28..db34c952d794 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/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/lib/Tooling/Refactoring/AtomicChange.cpp b/lib/Tooling/Refactoring/AtomicChange.cpp
new file mode 100644
index 000000000000..321bbfa2866a
--- /dev/null
+++ b/lib/Tooling/Refactoring/AtomicChange.cpp
@@ -0,0 +1,178 @@
+//===--- 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_FLOW_SEQUENCE_VECTOR(std::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/lib/Tooling/Refactoring/CMakeLists.txt b/lib/Tooling/Refactoring/CMakeLists.txt
new file mode 100644
index 000000000000..b2f9b4f4c0cd
--- /dev/null
+++ b/lib/Tooling/Refactoring/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(LLVM_LINK_COMPONENTS
+ Option
+ Support
+ )
+
+add_clang_library(clangToolingRefactor
+ AtomicChange.cpp
+
+ LINK_LIBS
+ clangBasic
+ clangToolingCore
+ )
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 25cee98078f3..9e1181281f13 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -244,7 +244,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);
diff --git a/test/ARCMT/lit.local.cfg b/test/ARCMT/lit.local.cfg
index 4b28d6dff8a3..e9b04164d69d 100644
--- a/test/ARCMT/lit.local.cfg
+++ b/test/ARCMT/lit.local.cfg
@@ -1,2 +1,2 @@
-if config.root.clang_arcmt == 0:
+if not config.root.clang_arcmt:
config.unsupported = True
diff --git a/test/ASTMerge/asm/Inputs/asm-function.cpp b/test/ASTMerge/asm/Inputs/asm-function.cpp
index 59c4edfbcd25..1b8783354fce 100644
--- a/test/ASTMerge/asm/Inputs/asm-function.cpp
+++ b/test/ASTMerge/asm/Inputs/asm-function.cpp
@@ -9,3 +9,13 @@ unsigned char asmFunc(unsigned char a, unsigned char b) {
res = bigres;
return res;
}
+
+int asmFunc2(int i) {
+ int res;
+ asm ("mov %1, %0 \t\n"
+ "inc %0 "
+ : "=r" (res)
+ : "r" (i)
+ : "cc");
+ return res;
+}
diff --git a/test/ASTMerge/asm/test.cpp b/test/ASTMerge/asm/test.cpp
index 3a0a205720fe..8c3bdfe17b75 100644
--- a/test/ASTMerge/asm/test.cpp
+++ b/test/ASTMerge/asm/test.cpp
@@ -4,4 +4,5 @@
void testAsmImport() {
asmFunc(12, 42);
+ asmFunc2(42);
}
diff --git a/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec1.cpp b/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec1.cpp
new file mode 100644
index 000000000000..43606d4d220b
--- /dev/null
+++ b/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec1.cpp
@@ -0,0 +1,118 @@
+template<typename T, class P>
+struct TwoOptionTemplate {};
+
+template<typename T>
+struct TwoOptionTemplate<T, char> {
+ int member;
+};
+
+
+template<typename T>
+struct TwoOptionTemplate<T, double> {
+ float member;
+};
+
+template<typename T>
+struct TwoOptionTemplate<T, T> {
+ T** member;
+};
+
+TwoOptionTemplate<int, char> X0;
+TwoOptionTemplate<int, float> X1;
+TwoOptionTemplate<void *, wchar_t> X2;
+TwoOptionTemplate<long, long> X3;
+TwoOptionTemplate<float, float> X4;
+TwoOptionTemplate<long, long> SingleSource;
+TwoOptionTemplate<char, double> SecondDoubleSource;
+
+
+template<int I, class C>
+struct IntTemplateSpec {};
+
+template<class C>
+struct IntTemplateSpec<4, C> {
+ C member;
+};
+
+template<int I>
+struct IntTemplateSpec<I, void *> {
+ int member;
+ static constexpr int val = I;
+};
+
+template<int I>
+struct IntTemplateSpec<I, double> {
+ char member;
+ static constexpr int val = I;
+};
+
+IntTemplateSpec<4, wchar_t> Y0;
+IntTemplateSpec<5, void *> Y1;
+IntTemplateSpec<1, long> Y2;
+IntTemplateSpec<3, int> Y3;
+//template<int I> constexpr int IntTemplateSpec<I, double>::val;
+IntTemplateSpec<42, double> NumberSource;
+static_assert(NumberSource.val == 42);
+
+namespace One {
+namespace Two {
+ // Just an empty namespace to ensure we can deal with multiple namespace decls.
+}
+}
+
+
+namespace One {
+namespace Two {
+namespace Three {
+
+template<class T>
+class Parent {};
+
+} // namespace Three
+
+} // namespace Two
+
+template<typename T, typename X>
+struct Child1: public Two::Three::Parent<unsigned> {
+ char member;
+};
+
+template<class T>
+struct Child1<T, One::Two::Three::Parent<T>> {
+ T member;
+};
+
+} // namespace One
+
+One::Child1<int, double> Z0Source;
+
+// Test import of nested namespace specifiers
+template<typename T>
+struct Outer {
+ template<typename U> class Inner0;
+};
+
+template<typename X>
+template<typename Y>
+class Outer<X>::Inner0 {
+public:
+ void f(X, Y);
+ template<typename Z> struct Inner1;
+};
+
+template<typename X>
+template<typename Y>
+void Outer<X>::Inner0<Y>::f(X, Y) {}
+
+template<typename X>
+template<typename Y>
+template<typename Z>
+class Outer<X>::Inner0<Y>::Inner1 {
+public:
+ void f(Y, Z);
+};
+
+template<typename X>
+template<typename Y>
+template<typename Z>
+void Outer<X>::Inner0<Y>::Inner1<Z>::f(Y, Z) {}
diff --git a/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec2.cpp b/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec2.cpp
new file mode 100644
index 000000000000..2f3f0c68e28c
--- /dev/null
+++ b/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec2.cpp
@@ -0,0 +1,79 @@
+template<typename T, typename P>
+struct TwoOptionTemplate {};
+
+template<typename T>
+struct TwoOptionTemplate<T, char> {
+ int member;
+};
+
+
+template<typename T>
+struct TwoOptionTemplate<T, double> {
+ float member;
+};
+
+template<typename T>
+struct TwoOptionTemplate<T, T> {
+ T** member;
+};
+
+TwoOptionTemplate<int, char> X0;
+TwoOptionTemplate<int, double> X1;
+TwoOptionTemplate<void *, wchar_t> X2;
+TwoOptionTemplate<long, long> X3;
+TwoOptionTemplate<int, int> X4;
+TwoOptionTemplate<long, long> SingleDest;
+TwoOptionTemplate<int, double> SecondDoubleDest;
+
+
+template<int I, class C>
+struct IntTemplateSpec {};
+
+template<class C>
+struct IntTemplateSpec<4, C> {
+ C member;
+};
+
+template<int I>
+struct IntTemplateSpec<I, void *> {
+ double member;
+ static constexpr int val = I;
+};
+
+template<int I>
+struct IntTemplateSpec<I, double> {
+ char member;
+ static constexpr int val = I;
+};
+
+IntTemplateSpec<4, wchar_t>Y0;
+IntTemplateSpec<5, void *> Y1;
+IntTemplateSpec<1, int> Y2;
+IntTemplateSpec<2, int> Y3;
+IntTemplateSpec<43, double> NumberDest;
+
+namespace One {
+namespace Two {
+namespace Three {
+
+template<class T>
+class Parent {};
+
+} // namespace Three
+
+} // namespace Two
+
+template<typename T, typename X>
+struct Child1: public Two::Three::Parent<unsigned> {
+ char member;
+};
+
+template<class T>
+struct Child1<T, One::Two::Three::Parent<T>> {
+ T member;
+};
+
+} // namespace One
+
+namespace Dst { One::Child1<double, One::Two::Three::Parent<double>> Z0Dst; }
+One::Child1<int, float> Z1;
diff --git a/test/ASTMerge/class-template-partial-spec/test.cpp b/test/ASTMerge/class-template-partial-spec/test.cpp
new file mode 100644
index 000000000000..cfa6052e7106
--- /dev/null
+++ b/test/ASTMerge/class-template-partial-spec/test.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -emit-pch -std=c++1z -o %t.1.ast %S/Inputs/class-template-partial-spec1.cpp
+// RUN: %clang_cc1 -emit-pch -std=c++1z -o %t.2.ast %S/Inputs/class-template-partial-spec2.cpp
+// RUN: not %clang_cc1 -std=c++1z -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+static_assert(sizeof(**SingleSource.member) == sizeof(**SingleDest.member));
+static_assert(sizeof(SecondDoubleSource.member) == sizeof(SecondDoubleDest.member));
+static_assert(NumberSource.val == 42);
+static_assert(sizeof(Z0Source.member) == sizeof(char));
+static_assert(sizeof(Dst::Z0Dst.member) == sizeof(double));
+static_assert(sizeof(One::Child1<double, One::Two::Three::Parent<double>>::member) == sizeof(double));
+
+// CHECK: class-template-partial-spec2.cpp:21:32: error: external variable 'X1' declared with incompatible types in different translation units ('TwoOptionTemplate<int, double>' vs. 'TwoOptionTemplate<int, float>')
+// CHECK: class-template-partial-spec1.cpp:21:31: note: declared here with type 'TwoOptionTemplate<int, float>'
+
+// CHECK: class-template-partial-spec2.cpp:24:29: error: external variable 'X4' declared with incompatible types in different translation units ('TwoOptionTemplate<int, int>' vs. 'TwoOptionTemplate<float, float>')
+// CHECK: class-template-partial-spec1.cpp:24:33: note: declared here with type 'TwoOptionTemplate<float, float>'
+
+// CHECK: class-template-partial-spec1.cpp:38:8: warning: type 'IntTemplateSpec<5, void *>' has incompatible definitions in different translation units
+// CHECK: class-template-partial-spec1.cpp:39:7: note: field 'member' has type 'int' here
+// CHECK: class-template-partial-spec2.cpp:39:10: note: field 'member' has type 'double' here
+
+// CHECK: class-template-partial-spec2.cpp:52:25: error: external variable 'Y3' declared with incompatible types in different translation units ('IntTemplateSpec<2, int>' vs. 'IntTemplateSpec<3, int>')
+// CHECK: class-template-partial-spec1.cpp:52:25: note: declared here with type 'IntTemplateSpec<3, int>'
+
+// CHECK-NOT: static_assert
diff --git a/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp b/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp
index 7ed8e338452f..2a33c35d9ea6 100644
--- a/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp
+++ b/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp
@@ -108,6 +108,10 @@ int testDefaultArg(int a = 2*2) {
return a;
}
+int testDefaultArgExpr() {
+ return testDefaultArg();
+}
+
template <typename T> // T has TemplateTypeParmType
void testTemplateTypeParmType(int i);
diff --git a/test/ASTMerge/exprs-cpp/test.cpp b/test/ASTMerge/exprs-cpp/test.cpp
index ba1f18b2c90c..0535aa85330f 100644
--- a/test/ASTMerge/exprs-cpp/test.cpp
+++ b/test/ASTMerge/exprs-cpp/test.cpp
@@ -41,5 +41,7 @@ void testImport(int *x, const S1 &cs1, S1 &s1) {
testScalarInit(42);
testOffsetOf();
testDefaultArg(12);
+ testDefaultArg();
+ testDefaultArgExpr();
useTemplateType();
}
diff --git a/test/ASTMerge/struct/Inputs/struct1.c b/test/ASTMerge/struct/Inputs/struct1.c
index af2af8abc42a..0f3e8b9bc3eb 100644
--- a/test/ASTMerge/struct/Inputs/struct1.c
+++ b/test/ASTMerge/struct/Inputs/struct1.c
@@ -61,3 +61,19 @@ struct {
Int i;
float f;
} x11;
+
+// Matches
+typedef struct {
+ Int i;
+ float f;
+} S12;
+
+S12 x12;
+
+// Mismatch
+typedef struct {
+ Float i; // Mismatch here.
+ float f;
+} S13;
+
+S13 x13;
diff --git a/test/ASTMerge/struct/Inputs/struct2.c b/test/ASTMerge/struct/Inputs/struct2.c
index 4b43df71d8d6..7fe17a576b23 100644
--- a/test/ASTMerge/struct/Inputs/struct2.c
+++ b/test/ASTMerge/struct/Inputs/struct2.c
@@ -58,3 +58,19 @@ struct {
int i;
float f;
} x11;
+
+// Matches
+typedef struct {
+ int i;
+ float f;
+} S12;
+
+S12 x12;
+
+// Mismatch
+typedef struct {
+ int i; // Mismatch here.
+ float f;
+} S13;
+
+S13 x13;
diff --git a/test/ASTMerge/struct/test.c b/test/ASTMerge/struct/test.c
index 4f41cea26b18..ed7750f6becc 100644
--- a/test/ASTMerge/struct/test.c
+++ b/test/ASTMerge/struct/test.c
@@ -39,4 +39,9 @@
// CHECK: struct2.c:53:43: note: field 'Deeper' has type 'struct DeeperError *' here
// CHECK: struct2.c:54:3: error: external variable 'xDeep' declared with incompatible types in different translation units ('struct DeepError' vs. 'struct DeepError')
// CHECK: struct1.c:57:3: note: declared here with type 'struct DeepError'
-// CHECK: 8 warnings and 7 errors generated
+// CHECK: struct1.c:74:9: warning: type 'S13' has incompatible definitions in different translation units
+// CHECK: struct1.c:75:9: note: field 'i' has type 'Float' (aka 'float') here
+// CHECK: struct2.c:72:7: note: field 'i' has type 'int' here
+// CHECK: struct2.c:76:5: error: external variable 'x13' declared with incompatible types in different translation units ('S13' vs. 'S13')
+// CHECK: struct1.c:79:5: note: declared here with type 'S13'
+// CHECK: 9 warnings and 8 errors generated
diff --git a/test/Analysis/CFContainers-invalid.c b/test/Analysis/CFContainers-invalid.c
index 3268e1eae253..ce1284f75da7 100644
--- a/test/Analysis/CFContainers-invalid.c
+++ b/test/Analysis/CFContainers-invalid.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues -triple x86_64-apple-darwin -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues -triple x86_64-apple-darwin -verify %s
// expected-no-diagnostics
typedef const struct __CFAllocator * CFAllocatorRef;
diff --git a/test/Analysis/CFContainers.mm b/test/Analysis/CFContainers.mm
index f315bc9f045c..0a45bffe5acf 100644
--- a/test/Analysis/CFContainers.mm
+++ b/test/Analysis/CFContainers.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues,osx.coreFoundation.containers.OutOfBounds -analyzer-store=region -triple x86_64-apple-darwin -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues,osx.coreFoundation.containers.OutOfBounds -analyzer-store=region -triple x86_64-apple-darwin -verify %s
typedef const struct __CFAllocator * CFAllocatorRef;
typedef const struct __CFString * CFStringRef;
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
index fae144f859a8..714e213f9577 100644
--- a/test/Analysis/CFDateGC.m
+++ b/test/Analysis/CFDateGC.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify -fobjc-gc %s -Wno-implicit-function-declaration
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify -fobjc-gc %s -Wno-implicit-function-declaration
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/CFNumber.c b/test/Analysis/CFNumber.c
index d7dd951b93ce..7ac65cc1d2b2 100644
--- a/test/Analysis/CFNumber.c
+++ b/test/Analysis/CFNumber.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
typedef signed long CFIndex;
typedef const struct __CFAllocator * CFAllocatorRef;
diff --git a/test/Analysis/CFRetainRelease_NSAssertionHandler.m b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
index be1f20de762c..f358ee64ceb4 100644
--- a/test/Analysis/CFRetainRelease_NSAssertionHandler.m
+++ b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -verify %s -analyzer-store=region
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -verify %s -analyzer-store=region
// expected-no-diagnostics
typedef struct objc_selector *SEL;
diff --git a/test/Analysis/CGColorSpace.c b/test/Analysis/CGColorSpace.c
index 8681e15d39e5..38f0512b0063 100644
--- a/test/Analysis/CGColorSpace.c
+++ b/test/Analysis/CGColorSpace.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
typedef struct CGColorSpace *CGColorSpaceRef;
extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m
index d126d29157b8..6de98e85efe3 100644
--- a/test/Analysis/CheckNSError.m
+++ b/test/Analysis/CheckNSError.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -verify -Wno-objc-root-class %s
typedef signed char BOOL;
diff --git a/test/Analysis/DeallocMissingRelease.m b/test/Analysis/DeallocMissingRelease.m
index 651f20a13621..91af2bd0a231 100644
--- a/test/Analysis/DeallocMissingRelease.m
+++ b/test/Analysis/DeallocMissingRelease.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-ios4.0 -DMACOS=0 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-macosx10.6.0 -DMACOS=1 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-darwin10 -fobjc-arc -fobjc-runtime-has-weak -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-ios4.0 -DMACOS=0 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-macosx10.6.0 -DMACOS=1 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-darwin10 -fobjc-arc -fobjc-runtime-has-weak -verify %s
#include "Inputs/system-header-simulator-for-objc-dealloc.h"
diff --git a/test/Analysis/DeallocUseAfterFreeErrors.m b/test/Analysis/DeallocUseAfterFreeErrors.m
index c131e71f44a1..2e1bdc41bb6e 100644
--- a/test/Analysis/DeallocUseAfterFreeErrors.m
+++ b/test/Analysis/DeallocUseAfterFreeErrors.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.SuperDealloc,debug.ExprInspection -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.SuperDealloc,debug.ExprInspection -analyzer-output=text -verify %s
void clang_analyzer_warnIfReached();
diff --git a/test/Analysis/DynamicTypePropagation.m b/test/Analysis/DynamicTypePropagation.m
index 79ef37c794d0..25a0ae35fd32 100644
--- a/test/Analysis/DynamicTypePropagation.m
+++ b/test/Analysis/DynamicTypePropagation.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.ObjCGenerics -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.ObjCGenerics -verify %s
#if !__has_feature(objc_generics)
# error Compiler does not support Objective-C generics?
diff --git a/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
index 6fab8bb668e8..b5e47b3355da 100644
--- a/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
+++ b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
#include "Inputs/system-header-simulator-for-malloc.h"
diff --git a/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp b/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
index bca223b6e04a..88435b866acd 100644
--- a/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
+++ b/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -analyzer-store region -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -analyzer-store region -std=c++11 -verify %s
// expected-no-diagnostics
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/Malloc+NewDelete_intersections.cpp b/test/Analysis/Malloc+NewDelete_intersections.cpp
index d10020dc8e66..9140e1f4a372 100644
--- a/test/Analysis/Malloc+NewDelete_intersections.cpp
+++ b/test/Analysis/Malloc+NewDelete_intersections.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -std=c++11 -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
diff --git a/test/Analysis/MemRegion.cpp b/test/Analysis/MemRegion.cpp
index 992b7f1f9767..b8f079a773df 100644
--- a/test/Analysis/MemRegion.cpp
+++ b/test/Analysis/MemRegion.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=optin.mpi.MPI-Checker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.mpi.MPI-Checker -verify %s
#include "MPIMock.h"
diff --git a/test/Analysis/MismatchedDeallocator-checker-test.mm b/test/Analysis/MismatchedDeallocator-checker-test.mm
index 3cc3e18c7c7c..b80f7df233dd 100644
--- a/test/Analysis/MismatchedDeallocator-checker-test.mm
+++ b/test/Analysis/MismatchedDeallocator-checker-test.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -verify %s
#include "Inputs/system-header-simulator-objc.h"
#include "Inputs/system-header-simulator-cxx.h"
diff --git a/test/Analysis/MismatchedDeallocator-path-notes.cpp b/test/Analysis/MismatchedDeallocator-path-notes.cpp
index 1c8c80cf21b9..118f23bca114 100644
--- a/test/Analysis/MismatchedDeallocator-path-notes.cpp
+++ b/test/Analysis/MismatchedDeallocator-path-notes.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.MismatchedDeallocator -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.MismatchedDeallocator -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void changePointee(int *p);
diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m
index 248dc514c876..bedd1e7fc25a 100644
--- a/test/Analysis/MissingDealloc.m
+++ b/test/Analysis/MissingDealloc.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -verify -triple x86_64-apple-darwin10 -fobjc-arc %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.cocoa.Dealloc -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.cocoa.Dealloc -fblocks -verify -triple x86_64-apple-darwin10 -fobjc-arc %s
#define NON_ARC !__has_feature(objc_arc)
diff --git a/test/Analysis/MisusedMovedObject.cpp b/test/Analysis/MisusedMovedObject.cpp
new file mode 100644
index 000000000000..44e055fd407b
--- /dev/null
+++ b/test/Analysis/MisusedMovedObject.cpp
@@ -0,0 +1,619 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.MisusedMovedObject -std=c++11 -verify -analyzer-output=text %s
+
+namespace std {
+
+template <typename>
+struct remove_reference;
+
+template <typename _Tp>
+struct remove_reference { typedef _Tp type; };
+
+template <typename _Tp>
+struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template <typename _Tp>
+struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template <typename _Tp>
+typename remove_reference<_Tp>::type &&move(_Tp &&__t) {
+ return static_cast<typename remove_reference<_Tp>::type &&>(__t);
+}
+
+template <typename _Tp>
+_Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
+ return static_cast<_Tp &&>(__t);
+}
+
+template <class T>
+void swap(T &a, T &b) {
+ T c(std::move(a));
+ a = std::move(b);
+ b = std::move(c);
+}
+
+} // namespace std
+
+class B {
+public:
+ B() = default;
+ B(const B &) = default;
+ B(B &&) = default;
+ void operator=(B &&b) {
+ return;
+ }
+ void foo() { return; }
+};
+
+class A {
+ int i;
+ double d;
+
+public:
+ B b;
+ A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {}
+ void moveconstruct(A &&other) {
+ std::swap(b, other.b);
+ std::swap(d, other.d);
+ std::swap(i, other.i);
+ return;
+ }
+ static A get() {
+ A v(12, 13);
+ return v;
+ }
+ A(A *a) {
+ moveconstruct(std::move(*a));
+ }
+ A(const A &other) : i(other.i), d(other.d), b(other.b) {}
+ A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { // expected-note {{'b' became 'moved-from' here}}
+ }
+ A(A &&other, char *k) {
+ moveconstruct(std::move(other));
+ }
+ void operator=(A &&other) {
+ moveconstruct(std::move(other));
+ return;
+ }
+ int getI() { return i; }
+ int foo() const;
+ void bar() const;
+ void reset();
+ void destroy();
+ void clear();
+ bool empty() const;
+ bool isEmpty() const;
+ operator bool() const;
+};
+
+int bignum();
+
+void moveInsideFunctionCall(A a) {
+ A b = std::move(a);
+}
+void leftRefCall(A &a) {
+ a.foo();
+}
+void rightRefCall(A &&a) {
+ a.foo();
+}
+void constCopyOrMoveCall(const A a) {
+ a.foo();
+}
+
+void copyOrMoveCall(A a) {
+ a.foo();
+}
+
+void simpleMoveCtorTest() {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+}
+
+void simpleMoveAssignementTest() {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+}
+
+void moveInInitListTest() {
+ struct S {
+ A a;
+ };
+ A a;
+ S s{std::move(a)}; // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+}
+
+// Don't report a bug if the variable was assigned to in the meantime.
+void reinitializationTest(int i) {
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ a = A();
+ a.foo();
+ }
+ {
+ A a;
+ if (i == 1) { // expected-note {{Assuming 'i' is not equal to 1}} expected-note {{Taking false branch}}
+ // expected-note@-1 {{Assuming 'i' is not equal to 1}} expected-note@-1 {{Taking false branch}}
+ A b;
+ b = std::move(a);
+ a = A();
+ }
+ if (i == 2) { // expected-note {{Assuming 'i' is not equal to 2}} expected-note {{Taking false branch}}
+ //expected-note@-1 {{Assuming 'i' is not equal to 2}} expected-note@-1 {{Taking false branch}}
+ a.foo(); // no-warning
+ }
+ }
+ {
+ A a;
+ if (i == 1) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
+ std::move(a);
+ }
+ if (i == 2) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
+ a = A();
+ a.foo();
+ }
+ }
+ // The built-in assignment operator should also be recognized as a
+ // reinitialization. (std::move() may be called on built-in types in template
+ // code.)
+ {
+ int a1 = 1, a2 = 2;
+ std::swap(a1, a2);
+ }
+ // A std::move() after the assignment makes the variable invalid again.
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ a = A();
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ }
+ // If a path exist where we not reinitialize the variable we report a bug.
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ if (i < 10) { // expected-note {{Assuming 'i' is >= 10}} expected-note {{Taking false branch}}
+ a = A();
+ }
+ if (i > 5) { // expected-note {{Taking true branch}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ }
+ }
+}
+
+// Using decltype on an expression is not a use.
+void decltypeIsNotUseTest() {
+ A a;
+ // A b(std::move(a));
+ decltype(a) other_a; // no-warning
+}
+
+void loopTest() {
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ rightRefCall(std::move(a)); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ rightRefCall(std::move(a)); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ leftRefCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ leftRefCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ constCopyOrMoveCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ constCopyOrMoveCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ moveInsideFunctionCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ moveInsideFunctionCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ copyOrMoveCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ copyOrMoveCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true. Entering loop body}} expected-note {{Loop condition is true. Entering loop body}}
+ constCopyOrMoveCall(std::move(a)); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}}
+ }
+ }
+
+ // Don't warn if we return after the move.
+ {
+ A a;
+ for (int i = 0; i < 3; ++i) {
+ a.bar();
+ if (a.foo() > 0) {
+ A b;
+ b = std::move(a); // no-warning
+ return;
+ }
+ }
+ }
+}
+
+//report a usage of a moved-from object only at the first use
+void uniqueTest(bool cond) {
+ A a(42, 42.0);
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+
+ if (cond) { // expected-note {{Assuming 'cond' is not equal to 0}} expected-note {{Taking true branch}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ }
+ if (cond) {
+ a.bar(); // no-warning
+ }
+
+ a.bar(); // no-warning
+}
+
+void uniqueTest2() {
+ A a;
+ A a1 = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+
+ A a2 = std::move(a); // no-warning
+ a.foo(); // no-warning
+}
+
+// There are exceptions where we assume in general that the method works fine
+//even on moved-from objects.
+void moveSafeFunctionsTest() {
+ A a;
+ A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.empty(); // no-warning
+ a.isEmpty(); // no-warning
+ (void)a; // no-warning
+ (bool)a; // expected-warning {{expression result unused}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+}
+
+void moveStateResetFunctionsTest() {
+ {
+ A a;
+ A b = std::move(a);
+ a.reset(); // no-warning
+ a.foo(); // no-warning
+ }
+ {
+ A a;
+ A b = std::move(a);
+ a.destroy(); // no-warning
+ a.foo(); // no-warning
+ }
+ {
+ A a;
+ A b = std::move(a);
+ a.clear(); // no-warning
+ a.foo(); // no-warning
+ }
+}
+
+// Moves or uses that occur as part of template arguments.
+template <int>
+class ClassTemplate {
+public:
+ void foo(A a);
+};
+
+template <int>
+void functionTemplate(A a);
+
+void templateArgIsNotUseTest() {
+ {
+ // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
+ // Google Test.
+ A a;
+ ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning
+ }
+ {
+ A a;
+ functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning
+ }
+}
+
+// Moves of global variables are not reported.
+A global_a;
+void globalVariablesTest() {
+ std::move(global_a);
+ global_a.foo(); // no-warning
+}
+
+// Moves of member variables.
+class memberVariablesTest {
+ A a;
+ static A static_a;
+
+ void f() {
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}}
+
+ b = std::move(static_a); // expected-note {{'static_a' became 'moved-from' here}}
+ static_a.foo(); // expected-warning {{Method call on a 'moved-from' object 'static_a'}} expected-note {{Method call on a 'moved-from' object 'static_a'}}
+ }
+};
+
+void PtrAndArrayTest() {
+ A *Ptr = new A(1, 1.5);
+ A Arr[10];
+ Arr[2] = std::move(*Ptr); // expected-note {{Became 'moved-from' here}}
+ (*Ptr).foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
+
+ Ptr = &Arr[1];
+ Arr[3] = std::move(Arr[1]); // expected-note {{Became 'moved-from' here}}
+ Ptr->foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
+
+ Arr[3] = std::move(Arr[2]); // expected-note {{Became 'moved-from' here}}
+ Arr[2].foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
+
+ Arr[2] = std::move(Arr[3]); // reinitialization
+ Arr[2].foo(); // no-warning
+}
+
+void exclusiveConditionsTest(bool cond) {
+ A a;
+ if (cond) {
+ A b;
+ b = std::move(a);
+ }
+ if (!cond) {
+ a.bar(); // no-warning
+ }
+}
+
+void differentBranchesTest(int i) {
+ // Don't warn if the use is in a different branch from the move.
+ {
+ A a;
+ if (i > 0) { // expected-note {{Assuming 'i' is > 0}} expected-note {{Taking true branch}}
+ A b;
+ b = std::move(a);
+ } else {
+ a.foo(); // no-warning
+ }
+ }
+ // Same thing, but with a ternary operator.
+ {
+ A a, b;
+ i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning // expected-note {{'?' condition is true}}
+ }
+ // A variation on the theme above.
+ {
+ A a;
+ a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is false}} expected-note {{'?' condition is false}}
+ }
+ // Same thing, but with a switch statement.
+ {
+ A a, b;
+ switch (i) { // expected-note {{Control jumps to 'case 1:' at line 448}}
+ case 1:
+ b = std::move(a); // no-warning
+ break; // expected-note {{Execution jumps to the end of the function}}
+ case 2:
+ a.foo(); // no-warning
+ break;
+ }
+ }
+ // However, if there's a fallthrough, we do warn.
+ {
+ A a, b;
+ switch (i) { // expected-note {{Control jumps to 'case 1:' at line 460}}
+ case 1:
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ case 2:
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ break;
+ }
+ }
+}
+
+void tempTest() {
+ A a = A::get();
+ A::get().foo(); // no-warning
+ for (int i = 0; i < bignum(); i++) {
+ A::get().foo(); // no-warning
+ }
+}
+
+void interFunTest1(A &a) {
+ a.bar(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+}
+
+void interFunTest2() {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ interFunTest1(a); // expected-note {{Calling 'interFunTest1'}}
+}
+
+void foobar(A a, int i);
+void foobar(int i, A a);
+
+void paramEvaluateOrderTest() {
+ A a;
+ foobar(std::move(a), a.getI()); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}}
+
+ //FALSE NEGATIVE since parameters evaluate order is undefined
+ foobar(a.getI(), std::move(a)); //no-warning
+}
+
+void not_known(A &a);
+void not_known(A *a);
+
+void regionAndPointerEscapeTest() {
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ not_known(a);
+ a.foo(); //no-warning
+ }
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ not_known(&a);
+ a.foo(); // no-warning
+ }
+}
+
+// A declaration statement containing multiple declarations sequences the
+// initializer expressions.
+void declarationSequenceTest() {
+ {
+ A a;
+ A a1 = a, a2 = std::move(a); // no-warning
+ }
+ {
+ A a;
+ A a1 = std::move(a), a2 = a; // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}}
+ }
+}
+
+// The logical operators && and || sequence their operands.
+void logicalOperatorsSequenceTest() {
+ {
+ A a;
+ if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
+ // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
+ //expected-note@-2 {{Taking false branch}} expected-note@-2 {{Taking false branch}}
+ A().bar();
+ }
+ }
+ // A variation: Negate the result of the && (which pushes the && further down
+ // into the AST).
+ {
+ A a;
+ if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
+ // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
+ // expected-note@-2 {{Taking true branch}} expected-note@-2 {{Taking true branch}}
+ A().bar();
+ }
+ }
+ {
+ A a;
+ if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is true}} expected-note@-1 {{Assuming the condition is false}}
+ // expected-note@-2 {{Left side of '&&' is false}} expected-note@-2 {{Left side of '&&' is true}}
+ // expected-note@-3 {{Taking false branch}}
+ A().bar();
+ }
+ }
+ {
+ A a;
+ if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is true}}
+ //expected-note@-1 {{Left side of '||' is true}}
+ //expected-note@-2 {{Taking true branch}}
+ A().bar();
+ }
+ }
+ {
+ A a;
+ if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is false}} expected-note@-1 {{Left side of '||' is false}}
+ A().bar();
+ }
+ }
+}
+
+// A range-based for sequences the loop variable declaration before the body.
+void forRangeSequencesTest() {
+ A v[2] = {A(), A()};
+ for (A &a : v) {
+ A b;
+ b = std::move(a); // no-warning
+ }
+}
+
+// If a variable is declared in an if statement, the declaration of the variable
+// (which is treated like a reinitialization by the check) is sequenced before
+// the evaluation of the condition (which constitutes a use).
+void ifStmtSequencesDeclAndConditionTest() {
+ for (int i = 0; i < 3; ++i) {
+ if (A a = A()) {
+ A b;
+ b = std::move(a); // no-warning
+ }
+ }
+}
+
+void subRegionMoveTest() {
+ {
+ A a;
+ B b = std::move(a.b); // expected-note {{'b' became 'moved-from' here}}
+ a.b.foo(); // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}}
+ }
+ {
+ A a;
+ A a1 = std::move(a); // expected-note {{Calling move constructor for 'A'}} expected-note {{Returning from move constructor for 'A'}}
+ a.b.foo(); // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}}
+ }
+ // Don't report a misuse if any SuperRegion is already reported.
+ {
+ A a;
+ A a1 = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ a.b.foo(); // no-warning
+ }
+}
diff --git a/test/Analysis/NSContainers.m b/test/Analysis/NSContainers.m
index c868459999da..ac33efc1174a 100644
--- a/test/Analysis/NSContainers.m
+++ b/test/Analysis/NSContainers.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-objc-literal-conversion -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops,debug.ExprInspection -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -Wno-objc-literal-conversion -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops,debug.ExprInspection -verify -Wno-objc-root-class %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m
index 53b18c205ef8..e65b0715a15f 100644
--- a/test/Analysis/NSPanel.m
+++ b/test/Analysis/NSPanel.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
// expected-no-diagnostics
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
index 1123d80ab2e8..a53fc1e56624 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-config mode=shallow -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -DOSATOMIC_USE_INLINED -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-config mode=shallow -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -DOSATOMIC_USE_INLINED -triple i386-apple-darwin10 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/NSWindow.m b/test/Analysis/NSWindow.m
index 44a97e42d6c4..e247ff18ceb0 100644
--- a/test/Analysis/NSWindow.m
+++ b/test/Analysis/NSWindow.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core,deadcode.DeadStores -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core,deadcode.DeadStores -analyzer-store=region -verify %s
// These declarations were reduced using Delta-Debugging from Foundation.h
// on Mac OS X. The test cases are below.
diff --git a/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp b/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
index 49358f6a2aba..987ed6a31fa8 100644
--- a/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
+++ b/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,unix.MismatchedDeallocator -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.MismatchedDeallocator -DLEAKS -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,unix.MismatchedDeallocator -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.MismatchedDeallocator -DLEAKS -std=c++11 -verify %s
// expected-no-diagnostics
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/NewDelete-checker-test.cpp b/test/Analysis/NewDelete-checker-test.cpp
index 78a0015ca532..66e837572bb0 100644
--- a/test/Analysis/NewDelete-checker-test.cpp
+++ b/test/Analysis/NewDelete-checker-test.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"
typedef __typeof__(sizeof(int)) size_t;
@@ -244,7 +244,7 @@ void testUninitDeleteArray() {
void testUninitFree() {
int *x;
- free(x); // expected-warning{{Function call argument is an uninitialized value}}
+ free(x); // expected-warning{{1st function call argument is an uninitialized value}}
}
void testUninitDeleteSink() {
diff --git a/test/Analysis/NewDelete-custom.cpp b/test/Analysis/NewDelete-custom.cpp
index d368889c968e..f06ff4a858e5 100644
--- a/test/Analysis/NewDelete-custom.cpp
+++ b/test/Analysis/NewDelete-custom.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,unix.Malloc -std=c++11 -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.Malloc -std=c++11 -DLEAKS -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,unix.Malloc -std=c++11 -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.Malloc -std=c++11 -DLEAKS -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"
#ifndef LEAKS
diff --git a/test/Analysis/NewDelete-intersections.mm b/test/Analysis/NewDelete-intersections.mm
index cde8122b7274..aa52c7902888 100644
--- a/test/Analysis/NewDelete-intersections.mm
+++ b/test/Analysis/NewDelete-intersections.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -std=c++11 -DLEAKS -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -std=c++11 -DLEAKS -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"
#include "Inputs/system-header-simulator-objc.h"
diff --git a/test/Analysis/NewDelete-path-notes.cpp b/test/Analysis/NewDelete-path-notes.cpp
index 64b15b88dfe8..115a4addcaa8 100644
--- a/test/Analysis/NewDelete-path-notes.cpp
+++ b/test/Analysis/NewDelete-path-notes.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=cplusplus.NewDelete,unix.Malloc -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=cplusplus.NewDelete,unix.Malloc -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.NewDelete,unix.Malloc -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.NewDelete,unix.Malloc -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void test() {
diff --git a/test/Analysis/NewDelete-variadic.cpp b/test/Analysis/NewDelete-variadic.cpp
index f9ef079bfe80..523785a70415 100644
--- a/test/Analysis/NewDelete-variadic.cpp
+++ b/test/Analysis/NewDelete-variadic.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.Malloc -std=c++11 -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.Malloc -std=c++11 -fblocks -verify %s
// expected-no-diagnostics
namespace std {
diff --git a/test/Analysis/NewDeleteLeaks-PR18394.cpp b/test/Analysis/NewDeleteLeaks-PR18394.cpp
index d0d70375f5a2..5a5b82cf609c 100644
--- a/test/Analysis/NewDeleteLeaks-PR18394.cpp
+++ b/test/Analysis/NewDeleteLeaks-PR18394.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyzer-config graph-trim-interval=1 -analyzer-max-loop 1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-config graph-trim-interval=1 -analyzer-max-loop 1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -verify %s
// expected-no-diagnostics
class A {
diff --git a/test/Analysis/NewDeleteLeaks-PR19102.cpp b/test/Analysis/NewDeleteLeaks-PR19102.cpp
index b141301e456f..502db6122f5c 100644
--- a/test/Analysis/NewDeleteLeaks-PR19102.cpp
+++ b/test/Analysis/NewDeleteLeaks-PR19102.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -verify %s
class A0 {};
diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m
index 5ed92dfe5d4e..c08fd0dc5156 100644
--- a/test/Analysis/NoReturn.m
+++ b/test/Analysis/NoReturn.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
#include <stdarg.h>
diff --git a/test/Analysis/OSAtomic_mac.cpp b/test/Analysis/OSAtomic_mac.cpp
index f93895893c59..e45f236b2f03 100644
--- a/test/Analysis/OSAtomic_mac.cpp
+++ b/test/Analysis/OSAtomic_mac.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,osx -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,osx -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
// expected-no-diagnostics
// Test handling of OSAtomicCompareAndSwap when C++ inserts "no-op" casts and we
diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m
index 201e3e165d87..1a112ec2b128 100644
--- a/test/Analysis/ObjCProperties.m
+++ b/test/Analysis/ObjCProperties.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s -verify
// expected-no-diagnostics
// The point of this test cases is to exercise properties in the static
diff --git a/test/Analysis/ObjCPropertiesSyntaxChecks.m b/test/Analysis/ObjCPropertiesSyntaxChecks.m
index 5c642c581736..5a25896c8aef 100644
--- a/test/Analysis/ObjCPropertiesSyntaxChecks.m
+++ b/test/Analysis/ObjCPropertiesSyntaxChecks.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -w -fblocks -analyze -analyzer-checker=osx.ObjCProperty %s -verify
+// RUN: %clang_analyze_cc1 -w -fblocks -analyzer-checker=osx.ObjCProperty %s -verify
#include "Inputs/system-header-simulator-objc.h"
@@ -59,3 +59,10 @@
@interface IWithoutImpl : NSObject {}
@property(copy) NSMutableString *mutableStr; // no-warning
@end
+
+@protocol SomeProtocol
+// Don't warn on protocol properties because it is possible to
+// conform to them correctly; it is only synthesized setters that
+// that are definitely incorrect.
+@property (copy) NSMutableString *myProp; // no-crash // no-warning
+@end
diff --git a/test/Analysis/ObjCRetSigs.m b/test/Analysis/ObjCRetSigs.m
index 6ee83ec4d105..97d33f9f5467 100644
--- a/test/Analysis/ObjCRetSigs.m
+++ b/test/Analysis/ObjCRetSigs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify -Wno-objc-root-class %s
int printf(const char *, ...);
diff --git a/test/Analysis/PR12905.c b/test/Analysis/PR12905.c
index 8f678d114472..f36b93aacf90 100644
--- a/test/Analysis/PR12905.c
+++ b/test/Analysis/PR12905.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core %s
// PR12905
void C(void);
diff --git a/test/Analysis/PR24184.cpp b/test/Analysis/PR24184.cpp
index 54eae563e7da..1280334d4d6a 100644
--- a/test/Analysis/PR24184.cpp
+++ b/test/Analysis/PR24184.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -w -analyze -analyzer-eagerly-assume -fcxx-exceptions -analyzer-checker=core -analyzer-checker=alpha.core.PointerArithm,alpha.core.CastToStruct -analyzer-max-loop 64 -verify %s
-// RUN: %clang_cc1 -w -analyze -analyzer-checker=core -analyzer-checker=cplusplus -fcxx-exceptions -analyzer-checker alpha.core.PointerArithm,alpha.core.CastToStruct -analyzer-max-loop 63 -verify %s
+// RUN: %clang_analyze_cc1 -w -analyzer-eagerly-assume -fcxx-exceptions -analyzer-checker=core -analyzer-checker=alpha.core.PointerArithm,alpha.core.CastToStruct -analyzer-max-loop 64 -verify %s
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core -analyzer-checker=cplusplus -fcxx-exceptions -analyzer-checker alpha.core.PointerArithm,alpha.core.CastToStruct -analyzer-max-loop 63 -verify %s
// These tests used to hit an assertion in the bug report. Test case from http://llvm.org/PR24184.
typedef struct {
diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m
index ac552ee613bd..1c2270e6aa66 100644
--- a/test/Analysis/PR2599.m
+++ b/test/Analysis/PR2599.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -fobjc-gc -verify %s
+// RUN: %clang_analyze_cc1 -triple %itanium_abi_triple -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -fobjc-gc -verify %s
typedef const void * CFTypeRef;
typedef const struct __CFString * CFStringRef;
diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m
index b609da5aac24..8b7effc66a1e 100644
--- a/test/Analysis/PR2978.m
+++ b/test/Analysis/PR2978.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,osx.cocoa.Dealloc %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,osx.cocoa.Dealloc %s -verify
// Tests for the checker which checks missing/extra ivar 'release' calls
// in dealloc.
diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m
index 68d5660287da..ffdb7b4a6e44 100644
--- a/test/Analysis/PR3991.m
+++ b/test/Analysis/PR3991.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -triple x86_64-apple-darwin9 -Wno-incomplete-implementation %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -triple x86_64-apple-darwin9 -Wno-incomplete-implementation %s
// expected-no-diagnostics
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/PR7218.c b/test/Analysis/PR7218.c
index 1775e057f4db..10a75c98e515 100644
--- a/test/Analysis/PR7218.c
+++ b/test/Analysis/PR7218.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store region -verify %s
char PR7218(char a) {
char buf[2];
buf[0] = a;
diff --git a/test/Analysis/additive-folding-range-constraints.c b/test/Analysis/additive-folding-range-constraints.c
index 4baada8bf98a..87d1b1cd8958 100644
--- a/test/Analysis/additive-folding-range-constraints.c
+++ b/test/Analysis/additive-folding-range-constraints.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/additive-folding.cpp b/test/Analysis/additive-folding.cpp
index 6ae025bbac2e..823b17600428 100644
--- a/test/Analysis/additive-folding.cpp
+++ b/test/Analysis/additive-folding.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -Wno-tautological-compare %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -Wno-tautological-compare %s
void clang_analyzer_eval(bool);
@@ -205,3 +205,12 @@ void multiplicativeSanityTest(int x) {
clang_analyzer_eval(x == 3); // expected-warning{{UNKNOWN}}
}
+
+void additiveSymSymFolding(int x, int y) {
+ // We should simplify 'x - 1' to '0' and handle the comparison,
+ // despite both sides being complicated symbols.
+ int z = x - 1;
+ if (x == 1)
+ if (y >= 0)
+ clang_analyzer_eval(z <= y); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/analyzeOneFunction.m b/test/Analysis/analyzeOneFunction.m
index e70b2d7d5fbc..a77abe1246b8 100644
--- a/test/Analysis/analyzeOneFunction.m
+++ b/test/Analysis/analyzeOneFunction.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyze-function="-[Test1 myMethodWithY:withX:]" -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyze-function="-[Test1 myMethodWithY:withX:]" -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/analyzer-checker-config.c b/test/Analysis/analyzer-checker-config.c
index 642c96c996d5..34e339963f3c 100644
--- a/test/Analysis/analyzer-checker-config.c
+++ b/test/Analysis/analyzer-checker-config.c
@@ -1,10 +1,10 @@
-// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.mallo:Optimistic=true 2>&1 | FileCheck %s
-// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config uni:Optimistic=true 2>&1 | FileCheck %s
-// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config uni.:Optimistic=true 2>&1 | FileCheck %s
-// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config ..:Optimistic=true 2>&1 | FileCheck %s
-// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.:Optimistic=true 2>&1 | FileCheck %s
-// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unrelated:Optimistic=true 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.Malloc:Optimistic=true
+// RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config unix.mallo:Optimistic=true 2>&1 | FileCheck %s
+// RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config uni:Optimistic=true 2>&1 | FileCheck %s
+// RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config uni.:Optimistic=true 2>&1 | FileCheck %s
+// RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config ..:Optimistic=true 2>&1 | FileCheck %s
+// RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config unix.:Optimistic=true 2>&1 | FileCheck %s
+// RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config unrelated:Optimistic=true 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config unix.Malloc:Optimistic=true
// Just to test clang is working.
# foo
diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c
index 6faeeb3bf733..c0153a50532a 100644
--- a/test/Analysis/analyzer-config.c
+++ b/test/Analysis/analyzer-config.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target x86_64-apple-darwin10 --analyze %s -o /dev/null -Xclang -analyzer-checker=debug.ConfigDumper -Xclang -analyzer-max-loop -Xclang 34 > %t 2>&1
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 %s -o /dev/null -analyzer-checker=core,osx.cocoa,debug.ConfigDumper -analyzer-max-loop 34 > %t 2>&1
// RUN: FileCheck --input-file=%t %s
void bar() {}
diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp
index 23f08286eb7e..f84be1781160 100644
--- a/test/Analysis/analyzer-config.cpp
+++ b/test/Analysis/analyzer-config.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -target x86_64-apple-darwin10 --analyze %s -o /dev/null -Xclang -analyzer-checker=debug.ConfigDumper -Xclang -analyzer-max-loop -Xclang 34 > %t 2>&1
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 %s -o /dev/null -analyzer-checker=core,osx.cocoa,debug.ConfigDumper -analyzer-max-loop 34 > %t 2>&1
// RUN: FileCheck --input-file=%t %s
void bar() {}
diff --git a/test/Analysis/analyzer-display-progress.cpp b/test/Analysis/analyzer-display-progress.cpp
index 5d9f5e5b28f0..b54044a0a361 100644
--- a/test/Analysis/analyzer-display-progress.cpp
+++ b/test/Analysis/analyzer-display-progress.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-display-progress %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-display-progress %s 2>&1 | FileCheck %s
void f() {};
void g() {};
diff --git a/test/Analysis/analyzer-display-progress.m b/test/Analysis/analyzer-display-progress.m
index cc43cf36d60e..8d0b3d6d5679 100644
--- a/test/Analysis/analyzer-display-progress.m
+++ b/test/Analysis/analyzer-display-progress.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-display-progress %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-display-progress %s 2>&1 | FileCheck %s
#include "Inputs/system-header-simulator-objc.h"
diff --git a/test/Analysis/analyzer-enabled-checkers.c b/test/Analysis/analyzer-enabled-checkers.c
index e60de05d47a3..0ea01a010af6 100644
--- a/test/Analysis/analyzer-enabled-checkers.c
+++ b/test/Analysis/analyzer-enabled-checkers.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target x86_64-apple-darwin10 --analyze %s -o /dev/null -Xclang -analyzer-checker=core -Xclang -analyzer-list-enabled-checkers > %t 2>&1
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 %s -o /dev/null -analyzer-checker=core -analyzer-list-enabled-checkers > %t 2>&1
// RUN: FileCheck --input-file=%t %s
// CHECK: OVERVIEW: Clang Static Analyzer Enabled Checkers List
diff --git a/test/Analysis/analyzer-stats.c b/test/Analysis/analyzer-stats.c
index a0a50cbc9343..5a40d196bb1f 100644
--- a/test/Analysis/analyzer-stats.c
+++ b/test/Analysis/analyzer-stats.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
int foo();
diff --git a/test/Analysis/analyzer_test.py b/test/Analysis/analyzer_test.py
new file mode 100644
index 000000000000..58df11a4ba47
--- /dev/null
+++ b/test/Analysis/analyzer_test.py
@@ -0,0 +1,28 @@
+import lit.formats
+import lit.TestRunner
+
+# Custom format class for static analyzer tests
+class AnalyzerTest(lit.formats.ShTest):
+
+ def execute(self, test, litConfig):
+ result = self.executeWithAnalyzeSubstitution(
+ test, litConfig, '-analyzer-constraints=range')
+
+ if result.code == lit.Test.FAIL:
+ return result
+
+ # If z3 backend available, add an additional run line for it
+ if test.config.clang_staticanalyzer_z3 == '1':
+ result = self.executeWithAnalyzeSubstitution(
+ test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3')
+
+ return result
+
+ def executeWithAnalyzeSubstitution(self, test, litConfig, substitution):
+ saved_substitutions = list(test.config.substitutions)
+ test.config.substitutions.append(('%analyze', substitution))
+ result = lit.TestRunner.executeShTest(test, litConfig,
+ self.execute_external)
+ test.config.substitutions = saved_substitutions
+
+ return result
diff --git a/test/Analysis/array-struct-region.c b/test/Analysis/array-struct-region.c
index a41d04018458..cdfec456cdae 100644
--- a/test/Analysis/array-struct-region.c
+++ b/test/Analysis/array-struct-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/array-struct-region.cpp b/test/Analysis/array-struct-region.cpp
index 47776863d6a2..48a05fd4057d 100644
--- a/test/Analysis/array-struct-region.cpp
+++ b/test/Analysis/array-struct-region.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c
index 34bdc58ab5ae..45c4c9d4ad17 100644
--- a/test/Analysis/array-struct.c
+++ b/test/Analysis/array-struct.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.CastToStruct -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.CastToStruct -analyzer-store=region -verify %s
struct s {
int data;
diff --git a/test/Analysis/atomics.c b/test/Analysis/atomics.c
index f0f5ff076842..6fe4ec580b86 100644
--- a/test/Analysis/atomics.c
+++ b/test/Analysis/atomics.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
// Tests for c11 atomics. Many of these tests currently yield unknown
// because we don't fully model the atomics and instead imprecisely
diff --git a/test/Analysis/auto-obj-dtors-cfg-output.cpp b/test/Analysis/auto-obj-dtors-cfg-output.cpp
index 0b4454fbd958..cc47c92360a5 100644
--- a/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -analyzer-checker=debug.DumpCFG %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
class A {
diff --git a/test/Analysis/base-init.cpp b/test/Analysis/base-init.cpp
index 3c870e1ccf88..1f59303789b3 100644
--- a/test/Analysis/base-init.cpp
+++ b/test/Analysis/base-init.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/bitwise-ops.c b/test/Analysis/bitwise-ops.c
index 01daf4229625..407aa19289c5 100644
--- a/test/Analysis/bitwise-ops.c
+++ b/test/Analysis/bitwise-ops.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -triple x86_64-apple-darwin13 -Wno-shift-count-overflow -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -triple x86_64-apple-darwin13 -Wno-shift-count-overflow -verify %s
void clang_analyzer_eval(int);
#define CHECK(expr) if (!(expr)) return; clang_analyzer_eval(expr)
diff --git a/test/Analysis/block-in-critical-section.cpp b/test/Analysis/block-in-critical-section.cpp
index 93c0b6dba665..c65cc612cf73 100644
--- a/test/Analysis/block-in-critical-section.cpp
+++ b/test/Analysis/block-in-critical-section.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.unix.BlockInCriticalSection -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.unix.BlockInCriticalSection -std=c++11 -verify %s
void sleep(int x) {}
@@ -9,29 +9,91 @@ struct mutex {
};
}
-void testBlockInCriticalSection() {
+void getc() {}
+void fgets() {}
+void read() {}
+void recv() {}
+
+void pthread_mutex_lock() {}
+void pthread_mutex_trylock() {}
+void pthread_mutex_unlock() {}
+
+void mtx_lock() {}
+void mtx_timedlock() {}
+void mtx_trylock() {}
+void mtx_unlock() {}
+
+void testBlockInCriticalSectionWithStdMutex() {
std::mutex m;
m.lock();
- sleep(3); // expected-warning {{A blocking function %s is called inside a critical section}}
+ sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+ getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
+ fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
+ read(); // expected-warning {{Call to blocking function 'read' inside of critical section}}
+ recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
m.unlock();
}
+void testBlockInCriticalSectionWithPthreadMutex() {
+ pthread_mutex_lock();
+ sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+ getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
+ fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
+ read(); // expected-warning {{Call to blocking function 'read' inside of critical section}}
+ recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
+ pthread_mutex_unlock();
+
+ pthread_mutex_trylock();
+ sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+ getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
+ fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
+ read(); // expected-warning {{Call to blocking function 'read' inside of critical section}}
+ recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
+ pthread_mutex_unlock();
+}
+
+void testBlockInCriticalSectionC11Locks() {
+ mtx_lock();
+ sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+ getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
+ fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
+ read(); // expected-warning {{Call to blocking function 'read' inside of critical section}}
+ recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
+ mtx_unlock();
+
+ mtx_timedlock();
+ sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+ getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
+ fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
+ read(); // expected-warning {{Call to blocking function 'read' inside of critical section}}
+ recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
+ mtx_unlock();
+
+ mtx_trylock();
+ sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+ getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
+ fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
+ read(); // expected-warning {{Call to blocking function 'read' inside of critical section}}
+ recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
+ mtx_unlock();
+}
+
void testBlockInCriticalSectionWithNestedMutexes() {
std::mutex m, n, k;
m.lock();
n.lock();
k.lock();
- sleep(3); // expected-warning {{A blocking function %s is called inside a critical section}}
+ sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
k.unlock();
- sleep(5); // expected-warning {{A blocking function %s is called inside a critical section}}
+ sleep(5); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
n.unlock();
- sleep(3); // expected-warning {{A blocking function %s is called inside a critical section}}
+ sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
m.unlock();
sleep(3); // no-warning
}
void f() {
- sleep(1000); // expected-warning {{A blocking function %s is called inside a critical section}}
+ sleep(1000); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
}
void testBlockInCriticalSectionInterProcedural() {
@@ -46,5 +108,5 @@ void testBlockInCriticalSectionUnexpectedUnlock() {
m.unlock();
sleep(1); // no-warning
m.lock();
- sleep(1); // expected-warning {{A blocking function %s is called inside a critical section}}
+ sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
}
diff --git a/test/Analysis/blocks-no-inline.c b/test/Analysis/blocks-no-inline.c
index de6f959b9d8c..859eedfbc3af 100644
--- a/test/Analysis/blocks-no-inline.c
+++ b/test/Analysis/blocks-no-inline.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -fblocks -verify -x c++ %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -fblocks -verify -x c++ %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/blocks.m b/test/Analysis/blocks.m
index bf10c61d3a21..98d0f8a2ebaa 100644
--- a/test/Analysis/blocks.m
+++ b/test/Analysis/blocks.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -analyzer-opt-analyze-nested-blocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -analyzer-opt-analyze-nested-blocks -verify -x objective-c++ %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -analyzer-store=region -fblocks -analyzer-opt-analyze-nested-blocks -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -analyzer-store=region -fblocks -analyzer-opt-analyze-nested-blocks -verify -x objective-c++ %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
diff --git a/test/Analysis/blocks.mm b/test/Analysis/blocks.mm
index 5f93888d45d0..6cff9b47f169 100644
--- a/test/Analysis/blocks.mm
+++ b/test/Analysis/blocks.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -fblocks -analyzer-opt-analyze-nested-blocks -verify -x objective-c++ %s
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG -fblocks -analyzer-opt-analyze-nested-blocks %s > %t 2>&1
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -fblocks -analyzer-opt-analyze-nested-blocks -verify -x objective-c++ %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpCFG -fblocks -analyzer-opt-analyze-nested-blocks %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
// expected-no-diagnostics
diff --git a/test/Analysis/bool-assignment.c b/test/Analysis/bool-assignment.c
index 285569ee11bb..57a7f0b5dc1b 100644
--- a/test/Analysis/bool-assignment.c
+++ b/test/Analysis/bool-assignment.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -x c++ %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -x c++ %s
// Test C++'s bool and C's _Bool.
// FIXME: We stopped warning on these when SValBuilder got smarter about
@@ -43,8 +43,11 @@ void test_BOOL_initialization(int y) {
return;
}
if (y > 200 && y < 250) {
- // FIXME: Currently we are loosing this warning due to a SymbolCast in RHS.
+#ifdef ANALYZER_CM_Z3
+ BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
+#else
BOOL x = y; // no-warning
+#endif
return;
}
if (y >= 127 && y < 150) {
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index 824aa7c063b7..a671d9ee8d4e 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===
// Declarations
diff --git a/test/Analysis/bstring.cpp b/test/Analysis/bstring.cpp
index 0b4e7e94f00b..a6d7b4016277 100644
--- a/test/Analysis/bstring.cpp
+++ b/test/Analysis/bstring.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
#include "Inputs/system-header-simulator-cxx.h"
#include "Inputs/system-header-simulator-for-malloc.h"
diff --git a/test/Analysis/bug_hash_test.cpp b/test/Analysis/bug_hash_test.cpp
index b73528e88d2f..0efcb5f7cdcd 100644
--- a/test/Analysis/bug_hash_test.cpp
+++ b/test/Analysis/bug_hash_test.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
int function(int p) {
diff --git a/test/Analysis/bug_hash_test.m b/test/Analysis/bug_hash_test.m
index debed329bdde..1e99d3c0b9ac 100644
--- a/test/Analysis/bug_hash_test.m
+++ b/test/Analysis/bug_hash_test.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
@protocol NSObject
diff --git a/test/Analysis/builtin-functions.cpp b/test/Analysis/builtin-functions.cpp
index d3afab5bd615..4e9859754d62 100644
--- a/test/Analysis/builtin-functions.cpp
+++ b/test/Analysis/builtin-functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection %s -std=c++11 -verify
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,debug.ExprInspection %s -std=c++11 -verify
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/call-invalidation.cpp b/test/Analysis/call-invalidation.cpp
index 80323ffcf18e..d3b5fca9cd5b 100644
--- a/test/Analysis/call-invalidation.cpp
+++ b/test/Analysis/call-invalidation.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/cast-to-struct.cpp b/test/Analysis/cast-to-struct.cpp
index 45d55947c937..c3aba023c56e 100644
--- a/test/Analysis/cast-to-struct.cpp
+++ b/test/Analysis/cast-to-struct.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.CastToStruct,core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.CastToStruct,core -verify %s
struct AB {
int A;
@@ -65,3 +65,17 @@ void intToStruct(int *P) {
void *VP = P;
Abc = (struct ABC *)VP;
}
+
+// https://llvm.org/bugs/show_bug.cgi?id=31173
+void dontCrash1(struct AB X) {
+ struct UndefS *S = (struct UndefS *)&X;
+}
+
+struct S;
+struct T {
+ struct S *P;
+};
+extern struct S Var1, Var2;
+void dontCrash2() {
+ ((struct T *) &Var1)->P = &Var2;
+}
diff --git a/test/Analysis/castexpr-callback.c b/test/Analysis/castexpr-callback.c
index 73fa17a134a8..3b46093db9ae 100644
--- a/test/Analysis/castexpr-callback.c
+++ b/test/Analysis/castexpr-callback.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.AnalysisOrder -analyzer-config debug.AnalysisOrder:PreStmtCastExpr=true,debug.AnalysisOrder:PostStmtCastExpr=true %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.AnalysisOrder -analyzer-config debug.AnalysisOrder:PreStmtCastExpr=true,debug.AnalysisOrder:PostStmtCastExpr=true %s 2>&1 | FileCheck %s
void test(char c) {
int i = (int)c;
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index b5e6e2784c8d..3ba12e4318de 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
extern void clang_analyzer_eval(_Bool);
@@ -118,3 +118,8 @@ void castsToBool() {
extern float globalFloat;
clang_analyzer_eval(globalFloat); // expected-warning{{UNKNOWN}}
}
+
+void locAsIntegerCasts(void *p) {
+ int x = (int) p;
+ clang_analyzer_eval(++x < 10); // no-crash // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/casts.cpp b/test/Analysis/casts.cpp
index 53e1cd085acd..f96f19b0ac33 100644
--- a/test/Analysis/casts.cpp
+++ b/test/Analysis/casts.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -verify %s
bool PR14634(int x) {
double y = (double)x;
diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m
index 895c8119c180..5c81ae6ffbe6 100644
--- a/test/Analysis/casts.m
+++ b/test/Analysis/casts.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
// Test function pointer casts.
diff --git a/test/Analysis/cfg.cpp b/test/Analysis/cfg.cpp
index 3e34a0fac6af..208277343cdc 100644
--- a/test/Analysis/cfg.cpp
+++ b/test/Analysis/cfg.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++11 %s > %t 2>&1
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++11 %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
// CHECK-LABEL: void checkWrap(int i)
diff --git a/test/Analysis/cfref_PR2519.c b/test/Analysis/cfref_PR2519.c
index d9642e5197d1..5636737ffe0e 100644
--- a/test/Analysis/cfref_PR2519.c
+++ b/test/Analysis/cfref_PR2519.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
typedef unsigned char Boolean;
diff --git a/test/Analysis/cfref_rdar6080742.c b/test/Analysis/cfref_rdar6080742.c
index 7094660a352d..2f7403658e8a 100644
--- a/test/Analysis/cfref_rdar6080742.c
+++ b/test/Analysis/cfref_rdar6080742.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
// This test case was reported in <rdar:problem/6080742>.
diff --git a/test/Analysis/check-deserialization.cpp b/test/Analysis/check-deserialization.cpp
index 2b0bce2b9ad5..9e4e47194c24 100644
--- a/test/Analysis/check-deserialization.cpp
+++ b/test/Analysis/check-deserialization.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t %s
-// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t -analyze -analyzer-checker=core %s
-// RUN: %clang_cc1 -include-pch %t -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -error-on-deserialized-decl S1_method -include-pch %t -analyzer-checker=core %s
+// RUN: %clang_analyze_cc1 -include-pch %t -analyzer-checker=core -verify %s
#ifndef HEADER
#define HEADER
diff --git a/test/Analysis/checker-plugins.c b/test/Analysis/checker-plugins.c
index 3882ba6661b4..ee60ec6e2192 100644
--- a/test/Analysis/checker-plugins.c
+++ b/test/Analysis/checker-plugins.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -load %llvmshlibdir/SampleAnalyzerPlugin%pluginext -analyze -analyzer-checker='example.MainCallChecker' -verify %s
+// RUN: %clang_analyze_cc1 -load %llvmshlibdir/SampleAnalyzerPlugin%pluginext -analyzer-checker='example.MainCallChecker' -verify %s
// REQUIRES: plugins, examples
// Test that the MainCallChecker example analyzer plugin loads and runs.
diff --git a/test/Analysis/chroot.c b/test/Analysis/chroot.c
index 1b818a8e6322..7e514f744000 100644
--- a/test/Analysis/chroot.c
+++ b/test/Analysis/chroot.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.unix.Chroot -analyzer-store region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.unix.Chroot -analyzer-store region -verify %s
extern int chroot(const char* path);
extern int chdir(const char* path);
diff --git a/test/Analysis/comparison-implicit-casts.cpp b/test/Analysis/comparison-implicit-casts.cpp
index a991d438cb4c..fe5254c0a53b 100644
--- a/test/Analysis/comparison-implicit-casts.cpp
+++ b/test/Analysis/comparison-implicit-casts.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -triple i386-apple-darwin9 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -triple x86_64-apple-darwin9 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,debug.ExprInspection -triple i386-apple-darwin9 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,debug.ExprInspection -triple x86_64-apple-darwin9 -verify %s
// This file runs in C++ mode so that the comparison type is 'bool', not 'int'.
void clang_analyzer_eval(int);
diff --git a/test/Analysis/complex-init-list.cpp b/test/Analysis/complex-init-list.cpp
index bbff64b7a13f..299f362ffd8a 100644
--- a/test/Analysis/complex-init-list.cpp
+++ b/test/Analysis/complex-init-list.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -verify %s
// expected-no-diagnostics
// Do not crash on initialization to complex numbers.
diff --git a/test/Analysis/complex.c b/test/Analysis/complex.c
index 6aca58948339..1f61b141cb31 100644
--- a/test/Analysis/complex.c
+++ b/test/Analysis/complex.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify -Wno-unreachable-code -ffreestanding %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -verify -Wno-unreachable-code -ffreestanding %s
#include <stdint.h>
diff --git a/test/Analysis/concrete-address.c b/test/Analysis/concrete-address.c
index 819afca967c9..f1608f8a801c 100644
--- a/test/Analysis/concrete-address.c
+++ b/test/Analysis/concrete-address.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
void foo() {
diff --git a/test/Analysis/conditional-operator.cpp b/test/Analysis/conditional-operator.cpp
index 137dc3987755..32978c66fa14 100644
--- a/test/Analysis/conditional-operator.cpp
+++ b/test/Analysis/conditional-operator.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection %s -analyzer-output=text -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection %s -analyzer-output=text -verify
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/conditional-path-notes.c b/test/Analysis/conditional-path-notes.c
index 448af7f97fae..d842b7fc6eef 100644
--- a/test/Analysis/conditional-path-notes.c
+++ b/test/Analysis/conditional-path-notes.c
@@ -1,5 +1,5 @@
-// RUN: %clang --analyze %s -Xanalyzer -analyzer-output=text -Xclang -verify
-// RUN: %clang --analyze %s -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -o %t
+// RUN: %clang_analyze_cc1 %s -analyzer-checker=core.NullDereference -analyzer-output=text -verify
+// RUN: %clang_analyze_cc1 %s -analyzer-checker=core.NullDereference -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t
// RUN: FileCheck --input-file=%t %s
void testCondOp(int *p) {
diff --git a/test/Analysis/const-method-call.cpp b/test/Analysis/const-method-call.cpp
index b8aaeea6c3eb..17df2a016b89 100644
--- a/test/Analysis/const-method-call.cpp
+++ b/test/Analysis/const-method-call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/constant-folding.c b/test/Analysis/constant-folding.c
index 81d119392658..a6d2b749427c 100644
--- a/test/Analysis/constant-folding.c
+++ b/test/Analysis/constant-folding.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/conversion.c b/test/Analysis/conversion.c
index f202696dc623..a22a56765407 100644
--- a/test/Analysis/conversion.c
+++ b/test/Analysis/conversion.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-conversion -analyze -analyzer-checker=core,alpha.core.Conversion -verify %s
+// RUN: %clang_analyze_cc1 -Wno-conversion -analyzer-checker=core,alpha.core.Conversion -verify %s
unsigned char U8;
signed char S8;
@@ -9,9 +9,67 @@ void assign(unsigned U, signed S) {
if (U > 300)
S8 = U; // expected-warning {{Loss of precision in implicit conversion}}
if (S > 10)
- U8 = S;
+ U8 = S; // no-warning
if (U < 200)
- S8 = U;
+ S8 = U; // no-warning
+}
+
+void addAssign() {
+ unsigned long L = 1000;
+ int I = -100;
+ U8 += L; // expected-warning {{Loss of precision in implicit conversion}}
+ L += I; // no-warning
+}
+
+void subAssign() {
+ unsigned long L = 1000;
+ int I = -100;
+ U8 -= L; // expected-warning {{Loss of precision in implicit conversion}}
+ L -= I; // no-warning
+}
+
+void mulAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 *= L; // expected-warning {{Loss of precision in implicit conversion}}
+ L *= I; // expected-warning {{Loss of sign in implicit conversion}}
+ I = 10;
+ L *= I; // no-warning
+}
+
+void divAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 /= L; // no-warning
+ L /= I; // expected-warning {{Loss of sign in implicit conversion}}
+}
+
+void remAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 %= L; // no-warning
+ L %= I; // expected-warning {{Loss of sign in implicit conversion}}
+}
+
+void andAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 &= L; // no-warning
+ L &= I; // expected-warning {{Loss of sign in implicit conversion}}
+}
+
+void orAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 |= L; // expected-warning {{Loss of precision in implicit conversion}}
+ L |= I; // expected-warning {{Loss of sign in implicit conversion}}
+}
+
+void xorAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 ^= L; // expected-warning {{Loss of precision in implicit conversion}}
+ L ^= I; // expected-warning {{Loss of sign in implicit conversion}}
}
void init1() {
@@ -21,7 +79,7 @@ void init1() {
void relational(unsigned U, signed S) {
if (S > 10) {
- if (U < S) {
+ if (U < S) { // no-warning
}
}
if (S < -10) {
@@ -32,14 +90,14 @@ void relational(unsigned U, signed S) {
void multiplication(unsigned U, signed S) {
if (S > 5)
- S = U * S;
+ S = U * S; // no-warning
if (S < -10)
S = U * S; // expected-warning {{Loss of sign}}
}
void division(unsigned U, signed S) {
if (S > 5)
- S = U / S;
+ S = U / S; // no-warning
if (S < -10)
S = U / S; // expected-warning {{Loss of sign}}
}
diff --git a/test/Analysis/copypaste/asm.cpp b/test/Analysis/copypaste/asm.cpp
index e93f119198a3..2e3613dfca4b 100644
--- a/test/Analysis/copypaste/asm.cpp
+++ b/test/Analysis/copypaste/asm.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -analyze -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/attributes.cpp b/test/Analysis/copypaste/attributes.cpp
index 72d654c6e060..083be74436df 100644
--- a/test/Analysis/copypaste/attributes.cpp
+++ b/test/Analysis/copypaste/attributes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/blocks.cpp b/test/Analysis/copypaste/blocks.cpp
index 133b5cbcd6ac..10467b7248c1 100644
--- a/test/Analysis/copypaste/blocks.cpp
+++ b/test/Analysis/copypaste/blocks.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -fblocks -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// This tests if we search for clones in blocks.
diff --git a/test/Analysis/copypaste/call.cpp b/test/Analysis/copypaste/call.cpp
index 8e95f7cb304a..046229a30a4a 100644
--- a/test/Analysis/copypaste/call.cpp
+++ b/test/Analysis/copypaste/call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/catch.cpp b/test/Analysis/copypaste/catch.cpp
index 590ce8f223f9..cf3e8076bd54 100644
--- a/test/Analysis/copypaste/catch.cpp
+++ b/test/Analysis/copypaste/catch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -fcxx-exceptions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/delete.cpp b/test/Analysis/copypaste/delete.cpp
index dc42c9c0595b..394226bedf1b 100644
--- a/test/Analysis/copypaste/delete.cpp
+++ b/test/Analysis/copypaste/delete.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/dependent-exist.cpp b/test/Analysis/copypaste/dependent-exist.cpp
index 5182ba61c9dc..9046353d0f07 100644
--- a/test/Analysis/copypaste/dependent-exist.cpp
+++ b/test/Analysis/copypaste/dependent-exist.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -fms-extensions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fms-extensions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/expr-types.cpp b/test/Analysis/copypaste/expr-types.cpp
index 14eef6eac636..601f0b192ac5 100644
--- a/test/Analysis/copypaste/expr-types.cpp
+++ b/test/Analysis/copypaste/expr-types.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/fold.cpp b/test/Analysis/copypaste/fold.cpp
index 548dfb19af56..0aed11bcf070 100644
--- a/test/Analysis/copypaste/fold.cpp
+++ b/test/Analysis/copypaste/fold.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/function-try-block.cpp b/test/Analysis/copypaste/function-try-block.cpp
index 7a69097579ab..d77714591b91 100644
--- a/test/Analysis/copypaste/function-try-block.cpp
+++ b/test/Analysis/copypaste/function-try-block.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -fcxx-exceptions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
// Tests if function try blocks are correctly handled.
diff --git a/test/Analysis/copypaste/functions.cpp b/test/Analysis/copypaste/functions.cpp
index c95443de72d1..d2c607b2171e 100644
--- a/test/Analysis/copypaste/functions.cpp
+++ b/test/Analysis/copypaste/functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// This tests if we search for clones in functions.
diff --git a/test/Analysis/copypaste/generic.c b/test/Analysis/copypaste/generic.c
index 9d8392139b39..d4d456473621 100644
--- a/test/Analysis/copypaste/generic.c
+++ b/test/Analysis/copypaste/generic.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/labels.cpp b/test/Analysis/copypaste/labels.cpp
index 26318ac40510..eff3330a0f39 100644
--- a/test/Analysis/copypaste/labels.cpp
+++ b/test/Analysis/copypaste/labels.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=gnu++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=gnu++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/lambda.cpp b/test/Analysis/copypaste/lambda.cpp
index c13c56f6671d..17c874894319 100644
--- a/test/Analysis/copypaste/lambda.cpp
+++ b/test/Analysis/copypaste/lambda.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/macro-complexity.cpp b/test/Analysis/copypaste/macro-complexity.cpp
index aca4df1d025c..70d3f0c74820 100644
--- a/test/Analysis/copypaste/macro-complexity.cpp
+++ b/test/Analysis/copypaste/macro-complexity.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// Tests that the complexity value of a macro expansion is about the same as
// the complexity value of a normal function call and the the macro body doesn't
diff --git a/test/Analysis/copypaste/macros.cpp b/test/Analysis/copypaste/macros.cpp
index db9b4c6ee2e4..bdacd4839a67 100644
--- a/test/Analysis/copypaste/macros.cpp
+++ b/test/Analysis/copypaste/macros.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// Tests that macros and non-macro clones aren't mixed into the same hash
// group. This is currently necessary as all clones in a hash group need
diff --git a/test/Analysis/copypaste/objc-methods.m b/test/Analysis/copypaste/objc-methods.m
index 9b8002c003a2..e63c7f6288bc 100644
--- a/test/Analysis/copypaste/objc-methods.m
+++ b/test/Analysis/copypaste/objc-methods.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -Wno-objc-root-class -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -Wno-objc-root-class -analyzer-checker=alpha.clone.CloneChecker -verify %s
// This tests if we search for clones in Objective-C methods.
diff --git a/test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp b/test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp
index 1180d447a7a3..7c4f35525fea 100644
--- a/test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp
+++ b/test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-output=plist -analyzer-config notes-as-events=true -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-output=plist -analyzer-config notes-as-events=true -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// RUN: FileCheck --input-file=%t.plist %s
void log();
diff --git a/test/Analysis/copypaste/plist-diagnostics.cpp b/test/Analysis/copypaste/plist-diagnostics.cpp
index 109d8e4fc71f..e2fa7597caf6 100644
--- a/test/Analysis/copypaste/plist-diagnostics.cpp
+++ b/test/Analysis/copypaste/plist-diagnostics.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-output=plist -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-output=plist -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// RUN: FileCheck --input-file=%t.plist %s
void log();
diff --git a/test/Analysis/copypaste/sub-sequences.cpp b/test/Analysis/copypaste/sub-sequences.cpp
index ff73632e4353..798662d25663 100644
--- a/test/Analysis/copypaste/sub-sequences.cpp
+++ b/test/Analysis/copypaste/sub-sequences.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
// This tests if sub-sequences can match with normal sequences.
diff --git a/test/Analysis/copypaste/suspicious-clones.cpp b/test/Analysis/copypaste/suspicious-clones.cpp
index c64a1dc8b8ff..3a760e256279 100644
--- a/test/Analysis/copypaste/suspicious-clones.cpp
+++ b/test/Analysis/copypaste/suspicious-clones.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:ReportSuspiciousClones=true -analyzer-config alpha.clone.CloneChecker:ReportNormalClones=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:ReportSuspiciousClones=true -analyzer-config alpha.clone.CloneChecker:ReportNormalClones=false -verify %s
// Tests finding a suspicious clone that references local variables.
diff --git a/test/Analysis/copypaste/text-diagnostics.cpp b/test/Analysis/copypaste/text-diagnostics.cpp
index a80afdb1eaf8..a6e358cc8535 100644
--- a/test/Analysis/copypaste/text-diagnostics.cpp
+++ b/test/Analysis/copypaste/text-diagnostics.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-output=text -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-output=text -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
void log();
diff --git a/test/Analysis/coverage.c b/test/Analysis/coverage.c
index 9e437d218272..b819f10edc13 100644
--- a/test/Analysis/coverage.c
+++ b/test/Analysis/coverage.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -analyzer-max-loop 4 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-store=region -analyzer-max-loop 4 -verify %s
#include "Inputs/system-header-simulator.h"
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/crash-trace.c b/test/Analysis/crash-trace.c
index bac74476ed9f..b79dd02e6b43 100644
--- a/test/Analysis/crash-trace.c
+++ b/test/Analysis/crash-trace.c
@@ -1,4 +1,4 @@
-// RUN: not --crash %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection %s 2>&1 | FileCheck %s
+// RUN: not --crash %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection %s 2>&1 | FileCheck %s
// REQUIRES: crash-recovery
// FIXME: CHECKs might be incompatible to win32.
diff --git a/test/Analysis/cstring-syntax-cxx.cpp b/test/Analysis/cstring-syntax-cxx.cpp
index 39c978ab600f..b2adef8e1ece 100644
--- a/test/Analysis/cstring-syntax-cxx.cpp
+++ b/test/Analysis/cstring-syntax-cxx.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -verify %s
// expected-no-diagnostics
// Ensure we don't crash on C++ declarations with special names.
diff --git a/test/Analysis/cstring-syntax.c b/test/Analysis/cstring-syntax.c
index 4aa88ed3b7ed..313ac5449540 100644
--- a/test/Analysis/cstring-syntax.c
+++ b/test/Analysis/cstring-syntax.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -Wno-strncat-size -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument -Wno-sizeof-pointer-memaccess -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -Wno-strncat-size -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument -Wno-sizeof-pointer-memaccess -verify %s
typedef __SIZE_TYPE__ size_t;
char *strncat(char *, const char *, size_t);
@@ -10,4 +10,6 @@ void testStrncat(const char *src) {
strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest)); // expected-warning {{Potential buffer overflow. Replace with}}
strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest)); // expected-warning {{Potential buffer overflow. Replace with}}
strncat(dest, src, sizeof(src)); // expected-warning {{Potential buffer overflow. Replace with}}
+ // Should not crash when sizeof has a type argument.
+ strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(char));
}
diff --git a/test/Analysis/ctor.mm b/test/Analysis/ctor.mm
index e7c0c6cac630..646229aac989 100644
--- a/test/Analysis/ctor.mm
+++ b/test/Analysis/ctor.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s
#include "Inputs/system-header-simulator-cxx.h"
diff --git a/test/Analysis/cxx-crashes.cpp b/test/Analysis/cxx-crashes.cpp
index e3f812540d0b..f8234c99ef5e 100644
--- a/test/Analysis/cxx-crashes.cpp
+++ b/test/Analysis/cxx-crashes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
// REQUIRES: LP64
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/cxx-for-range.cpp b/test/Analysis/cxx-for-range.cpp
index 6be8b78ee816..bf3cfbff1231 100644
--- a/test/Analysis/cxx-for-range.cpp
+++ b/test/Analysis/cxx-for-range.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core -analyzer-config path-diagnostics-alternate=true -analyzer-output=plist-multi-file -o %t.plist -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core -analyzer-config path-diagnostics-alternate=true -analyzer-output=plist-multi-file -o %t.plist -verify %s
// RUN: FileCheck --input-file=%t.plist %s
extern void work();
diff --git a/test/Analysis/cxx-method-names.cpp b/test/Analysis/cxx-method-names.cpp
index 21be5e4bd3f4..e57e72df840e 100644
--- a/test/Analysis/cxx-method-names.cpp
+++ b/test/Analysis/cxx-method-names.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix,osx,alpha.unix,alpha.security.taint -analyzer-store region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,osx,alpha.unix,alpha.security.taint -analyzer-store region -verify %s
// expected-no-diagnostics
class Evil {
diff --git a/test/Analysis/cxx11-crashes.cpp b/test/Analysis/cxx11-crashes.cpp
index c6034e6480ee..8905d1c87b82 100644
--- a/test/Analysis/cxx11-crashes.cpp
+++ b/test/Analysis/cxx11-crashes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -std=c++11 -verify %s
// radar://11485149, PR12871
class PlotPoint {
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index c55b34ff2112..05bc64af7a37 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores -analyzer-store=region -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -Wunused-variable -analyzer-checker=core,deadcode.DeadStores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -Wunused-variable -analyzer-checker=core,deadcode.DeadStores -analyzer-store=region -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
void f1() {
int k, y; // expected-warning{{unused variable 'k'}} expected-warning{{unused variable 'y'}}
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
index 77b349edd091..d926ccf5ecf6 100644
--- a/test/Analysis/dead-stores.cpp
+++ b/test/Analysis/dead-stores.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 -analyze -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 -analyze -analyzer-store=region -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 -analyzer-store=region -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
//===----------------------------------------------------------------------===//
// Basic dead store checking (but in C++ mode).
diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m
index 8bc6b2e84d01..9f91f393a116 100644
--- a/test/Analysis/dead-stores.m
+++ b/test/Analysis/dead-stores.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s
// expected-no-diagnostics
typedef signed char BOOL;
diff --git a/test/Analysis/debug-CallGraph.c b/test/Analysis/debug-CallGraph.c
index 64259e2069a4..9f3865b35a4e 100644
--- a/test/Analysis/debug-CallGraph.c
+++ b/test/Analysis/debug-CallGraph.c
@@ -1,4 +1,16 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCallGraph %s -fblocks 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s -fblocks 2>&1 | FileCheck %s
+
+int get5() {
+ return 5;
+}
+
+int add(int val1, int val2) {
+ return val1 + val2;
+}
+
+int test_add() {
+ return add(10, get5());
+}
static void mmm(int y) {
if (y != 0)
@@ -31,8 +43,18 @@ void eee();
void eee() {}
void fff() { eee(); }
+// This test case tests that forward declaration for the top-level function
+// does not affect call graph construction.
+void do_nothing() {}
+void test_single_call();
+void test_single_call() {
+ do_nothing();
+}
+
// CHECK:--- Call graph Dump ---
-// CHECK-NEXT: {{Function: < root > calls: mmm foo aaa < > bbb ccc ddd eee fff $}}
+// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call $}}
+// CHECK-NEXT: {{Function: test_single_call calls: do_nothing $}}
+// CHECK-NEXT: {{Function: do_nothing calls: $}}
// CHECK-NEXT: {{Function: fff calls: eee $}}
// CHECK-NEXT: {{Function: eee calls: $}}
// CHECK-NEXT: {{Function: ddd calls: ccc $}}
@@ -42,3 +64,6 @@ void fff() { eee(); }
// CHECK-NEXT: {{Function: aaa calls: foo $}}
// CHECK-NEXT: {{Function: foo calls: mmm $}}
// CHECK-NEXT: {{Function: mmm calls: $}}
+// CHECK-NEXT: {{Function: test_add calls: add get5 $}}
+// CHECK-NEXT: {{Function: add calls: $}}
+// CHECK-NEXT: {{Function: get5 calls: $}}
diff --git a/test/Analysis/default-analyze.m b/test/Analysis/default-analyze.m
index 5fbaa2f98c65..e2f7297884d7 100644
--- a/test/Analysis/default-analyze.m
+++ b/test/Analysis/default-analyze.m
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze %s -o %t
+// RUN: %clang_analyze_cc1 %s -o %t
// Tests that some specific checkers are enabled by default.
diff --git a/test/Analysis/default-diagnostic-visitors.c b/test/Analysis/default-diagnostic-visitors.c
index 0bc6a033ac09..c8f64bc6d7f4 100644
--- a/test/Analysis/default-diagnostic-visitors.c
+++ b/test/Analysis/default-diagnostic-visitors.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -analyzer-store=region -analyzer-output=text -verify %s
// This file is for testing enhanced diagnostics produced by the default BugReporterVisitors.
diff --git a/test/Analysis/delayed-template-parsing-crash.cpp b/test/Analysis/delayed-template-parsing-crash.cpp
index 94a143b0c066..6d189afb455a 100644
--- a/test/Analysis/delayed-template-parsing-crash.cpp
+++ b/test/Analysis/delayed-template-parsing-crash.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -std=c++11 -fdelayed-template-parsing -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -std=c++11 -fdelayed-template-parsing -verify %s
// expected-no-diagnostics
template <class T> struct remove_reference {typedef T type;};
diff --git a/test/Analysis/delegates.m b/test/Analysis/delegates.m
index 28e9006c18e5..23028054517e 100644
--- a/test/Analysis/delegates.m
+++ b/test/Analysis/delegates.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -Wno-objc-root-class -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -Wno-objc-root-class -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/derived-to-base.cpp b/test/Analysis/derived-to-base.cpp
index e9c7ca8f731f..b9851fd3e404 100644
--- a/test/Analysis/derived-to-base.cpp
+++ b/test/Analysis/derived-to-base.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
diff --git a/test/Analysis/designated-initializer.c b/test/Analysis/designated-initializer.c
index b601f872571f..920b2f08d7e7 100644
--- a/test/Analysis/designated-initializer.c
+++ b/test/Analysis/designated-initializer.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 \
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG %s 2>&1 \
// RUN: | FileCheck %s
struct Q { int a, b, c; };
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.c b/test/Analysis/diagnostics/deref-track-symbolic-region.c
index 42060ccd9260..179e736ee18b 100644
--- a/test/Analysis/diagnostics/deref-track-symbolic-region.c
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
struct S {
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.cpp b/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
index 6d348415aaf3..61993f0872f4 100644
--- a/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -verify %s
struct S {
int *x;
diff --git a/test/Analysis/diagnostics/diag-cross-file-boundaries.c b/test/Analysis/diagnostics/diag-cross-file-boundaries.c
index 270163e85607..b975af3fb29f 100644
--- a/test/Analysis/diagnostics/diag-cross-file-boundaries.c
+++ b/test/Analysis/diagnostics/diag-cross-file-boundaries.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=html -o PR12421.html %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=html -o PR12421.html %s 2>&1 | FileCheck %s
// Test for PR12421
#include "diag-cross-file-boundaries.h"
diff --git a/test/Analysis/diagnostics/explicit-suppression.cpp b/test/Analysis/diagnostics/explicit-suppression.cpp
index d36def20f25f..193846c082bc 100644
--- a/test/Analysis/diagnostics/explicit-suppression.cpp
+++ b/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config suppress-c++-stdlib=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config suppress-c++-stdlib=true -DSUPPRESSED=1 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config suppress-c++-stdlib=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config suppress-c++-stdlib=true -DSUPPRESSED=1 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DSUPPRESSED=1 -verify %s
#ifdef SUPPRESSED
// expected-no-diagnostics
diff --git a/test/Analysis/diagnostics/false-positive-suppression.c b/test/Analysis/diagnostics/false-positive-suppression.c
index cdcd7cc77798..87c04cbcdc07 100644
--- a/test/Analysis/diagnostics/false-positive-suppression.c
+++ b/test/Analysis/diagnostics/false-positive-suppression.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -I %S/Inputs -analyze -analyzer-checker=core,unix -verify %s
+// RUN: %clang_analyze_cc1 -I %S/Inputs -analyzer-checker=core,unix -verify %s
// expected-no-diagnostics
#include "include/sys/queue.h"
diff --git a/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp b/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
index 143cbbeeac20..197fad5d0b7d 100644
--- a/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
+++ b/test/Analysis/diagnostics/implicit-cxx-std-suppression.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -std=c++11 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/diagnostics/macros.cpp b/test/Analysis/diagnostics/macros.cpp
index 8d7fccde1c61..5aa2c03ab0ed 100644
--- a/test/Analysis/diagnostics/macros.cpp
+++ b/test/Analysis/diagnostics/macros.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,osx -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,osx -analyzer-output=text -verify %s
#include "../Inputs/system-header-simulator.h"
#include "../Inputs/system-header-simulator-cxx.h"
diff --git a/test/Analysis/diagnostics/macros.m b/test/Analysis/diagnostics/macros.m
index 7ef80b302dd9..b45997486214 100644
--- a/test/Analysis/diagnostics/macros.m
+++ b/test/Analysis/diagnostics/macros.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -fblocks -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -fblocks -analyzer-output=text -verify %s
#include "../Inputs/system-header-simulator-objc.h"
diff --git a/test/Analysis/diagnostics/no-prune-paths.c b/test/Analysis/diagnostics/no-prune-paths.c
index fab5cf82059b..6e9e45766bf5 100644
--- a/test/Analysis/diagnostics/no-prune-paths.c
+++ b/test/Analysis/diagnostics/no-prune-paths.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config prune-paths=false -DNPRUNE=1 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -analyzer-config prune-paths=false -DNPRUNE=1 -verify %s
// "prune-paths" is a debug option only; this is just a simple test to see that
// it's being honored.
diff --git a/test/Analysis/diagnostics/plist-diagnostics-include-check.cpp b/test/Analysis/diagnostics/plist-diagnostics-include-check.cpp
index 6ed39451a8bc..8c66b96007eb 100644
--- a/test/Analysis/diagnostics/plist-diagnostics-include-check.cpp
+++ b/test/Analysis/diagnostics/plist-diagnostics-include-check.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -analyzer-output=plist-multi-file %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
#include "Inputs/include/plist-diagnostics-include-check-macro.h"
diff --git a/test/Analysis/diagnostics/report-issues-within-main-file.cpp b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
index 5fd7abd03c4a..784fdba972df 100644
--- a/test/Analysis/diagnostics/report-issues-within-main-file.cpp
+++ b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -analyzer-output=plist-multi-file -analyzer-config report-in-main-source-file=true -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -analyzer-output=plist-multi-file -analyzer-config report-in-main-source-file=true -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
#include "Inputs/include/report-issues-within-main-file.h"
diff --git a/test/Analysis/diagnostics/shortest-path-suppression.c b/test/Analysis/diagnostics/shortest-path-suppression.c
index 4f648b986b25..d0fa4b51ef44 100644
--- a/test/Analysis/diagnostics/shortest-path-suppression.c
+++ b/test/Analysis/diagnostics/shortest-path-suppression.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=true -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-null-return-paths=true -analyzer-output=text -verify %s
// expected-no-diagnostics
int *returnNull() { return 0; }
diff --git a/test/Analysis/diagnostics/text-diagnostics.c b/test/Analysis/diagnostics/text-diagnostics.c
index 592521672ff4..01946476e099 100644
--- a/test/Analysis/diagnostics/text-diagnostics.c
+++ b/test/Analysis/diagnostics/text-diagnostics.c
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze -Xanalyzer -analyzer-output=text -fno-caret-diagnostics %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.NullDereference -analyzer-output=text -fno-caret-diagnostics %s 2>&1 | FileCheck %s
void testA() {
int *p = 0;
diff --git a/test/Analysis/diagnostics/undef-value-caller.c b/test/Analysis/diagnostics/undef-value-caller.c
index dc19e0a2b856..4f273bd9a72d 100644
--- a/test/Analysis/diagnostics/undef-value-caller.c
+++ b/test/Analysis/diagnostics/undef-value-caller.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
// RUN: FileCheck --input-file %t %s
#include "undef-value-callee.h"
diff --git a/test/Analysis/diagnostics/undef-value-param.c b/test/Analysis/diagnostics/undef-value-param.c
index 8ebf0daf2b49..837b0419ef20 100644
--- a/test/Analysis/diagnostics/undef-value-param.c
+++ b/test/Analysis/diagnostics/undef-value-param.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void foo_irrelevant(int c) {
diff --git a/test/Analysis/diagnostics/undef-value-param.m b/test/Analysis/diagnostics/undef-value-param.m
index b9947d8ce019..f8212e0b9df3 100644
--- a/test/Analysis/diagnostics/undef-value-param.m
+++ b/test/Analysis/diagnostics/undef-value-param.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
typedef signed char BOOL;
@@ -45,8 +45,8 @@ SCDynamicStoreRef anotherCreateRef(unsigned *err, unsigned x);
CreateRefUndef(&storeRef, 4);
//expected-note@-1{{Calling 'CreateRefUndef'}}
//expected-note@-2{{Returning from 'CreateRefUndef'}}
- CFRelease(storeRef); //expected-warning {{Function call argument is an uninitialized value}}
- //expected-note@-1{{Function call argument is an uninitialized value}}
+ CFRelease(storeRef); //expected-warning {{1st function call argument is an uninitialized value}}
+ //expected-note@-1{{1st function call argument is an uninitialized value}}
}
@end
@@ -918,12 +918,12 @@ static void CreateRefUndef(SCDynamicStoreRef *storeRef, unsigned x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Function call argument is an uninitialized value</string>
+// CHECK-NEXT: <string>1st function call argument is an uninitialized value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Function call argument is an uninitialized value</string>
+// CHECK-NEXT: <string>1st function call argument is an uninitialized value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>Function call argument is an uninitialized value</string>
+// CHECK-NEXT: <key>description</key><string>1st function call argument is an uninitialized value</string>
// CHECK-NEXT: <key>category</key><string>Logic error</string>
// CHECK-NEXT: <key>type</key><string>Uninitialized argument value</string>
// CHECK-NEXT: <key>check_name</key><string>core.CallAndMessage</string>
diff --git a/test/Analysis/disable-all-checks.c b/test/Analysis/disable-all-checks.c
index 461e6d9bf94a..eb55799c259f 100644
--- a/test/Analysis/disable-all-checks.c
+++ b/test/Analysis/disable-all-checks.c
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-disable-all-checks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-disable-all-checks -analyzer-checker=core -analyzer-store=region -verify %s
-// RUN: %clang --analyze -Xanalyzer -analyzer-disable-all-checks -Xclang -verify %s
-// RUN: not %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-disable-checker -verify %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -analyzer-disable-all-checks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-disable-all-checks -analyzer-checker=core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-disable-all-checks -verify %s
+// RUN: not %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -analyzer-disable-checker -verify %s 2>&1 | FileCheck %s
// expected-no-diagnostics
// CHECK: use -analyzer-disable-all-checks to disable all static analyzer checkers
int buggy() {
int x = 0;
return 5/x; // no warning
-} \ No newline at end of file
+}
diff --git a/test/Analysis/dispatch-once.m b/test/Analysis/dispatch-once.m
index 2f82718663e5..7314dc96d541 100644
--- a/test/Analysis/dispatch-once.m
+++ b/test/Analysis/dispatch-once.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -w -fblocks -analyze -analyzer-checker=core,osx.API,unix.Malloc -verify %s
-// RUN: %clang_cc1 -w -fblocks -fobjc-arc -analyze -analyzer-checker=core,osx.API,unix.Malloc -verify %s
+// RUN: %clang_analyze_cc1 -w -fblocks -analyzer-checker=core,osx.API,unix.Malloc -verify %s
+// RUN: %clang_analyze_cc1 -w -fblocks -fobjc-arc -analyzer-checker=core,osx.API,unix.Malloc -verify %s
#include "Inputs/system-header-simulator-objc.h"
diff --git a/test/Analysis/div-zero.cpp b/test/Analysis/div-zero.cpp
index d1261dc57335..063450d8883b 100644
--- a/test/Analysis/div-zero.cpp
+++ b/test/Analysis/div-zero.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.DivideZero -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -verify %s
int fooPR10616 (int qX ) {
int a, c, d;
diff --git a/test/Analysis/division-by-zero.c b/test/Analysis/division-by-zero.c
index d3c228e6c97d..33bb6fa3a6f5 100644
--- a/test/Analysis/division-by-zero.c
+++ b/test/Analysis/division-by-zero.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc %s
// Do not crash due to division by zero
int f(unsigned int a) {
diff --git a/test/Analysis/domtest.c b/test/Analysis/domtest.c
index dd72117f8c95..e957c8d70e02 100644
--- a/test/Analysis/domtest.c
+++ b/test/Analysis/domtest.c
@@ -1,5 +1,5 @@
// RUN: rm -f %t
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpDominators %s > %t 2>&1
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpDominators %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
// Test the DominatorsTree implementation with various control flows
diff --git a/test/Analysis/dtor-cxx11.cpp b/test/Analysis/dtor-cxx11.cpp
index 7d2e87e44e4b..76d5e6c5065d 100644
--- a/test/Analysis/dtor-cxx11.cpp
+++ b/test/Analysis/dtor-cxx11.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true -Wno-null-dereference -verify %s
// expected-no-diagnostics
#include "Inputs/system-header-simulator-cxx.h"
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index c67722283ff8..bc74130b2fdf 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -Wno-inaccessible-base -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -Wno-inaccessible-base -verify %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
diff --git a/test/Analysis/dtors-in-dtor-cfg-output.cpp b/test/Analysis/dtors-in-dtor-cfg-output.cpp
index ceda58c8566c..4c1c8dd91da7 100644
--- a/test/Analysis/dtors-in-dtor-cfg-output.cpp
+++ b/test/Analysis/dtors-in-dtor-cfg-output.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
class A {
public:
diff --git a/test/Analysis/dynamic-cast.cpp b/test/Analysis/dynamic-cast.cpp
index b48ee5b8efad..0c86f81cb819 100644
--- a/test/Analysis/dynamic-cast.cpp
+++ b/test/Analysis/dynamic-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -verify %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/dynamic_type_check.m b/test/Analysis/dynamic_type_check.m
index f9b181e308a9..3dc9465cfedf 100644
--- a/test/Analysis/dynamic_type_check.m
+++ b/test/Analysis/dynamic_type_check.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.DynamicTypeChecker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.DynamicTypeChecker -verify %s
#define nil 0
diff --git a/test/Analysis/edges-new.mm b/test/Analysis/edges-new.mm
index 5cc21e04ece0..217cd4aa467f 100644
--- a/test/Analysis/edges-new.mm
+++ b/test/Analysis/edges-new.mm
@@ -1,4 +1,4 @@
-// RUN: %clang -target x86_64-apple-darwin10 --analyze -Xclang -analyzer-config -Xclang path-diagnostics-alternate=true -Xclang -analyzer-output=plist -o %t %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,deadcode.DeadStores,osx.cocoa.RetainCount,unix.Malloc,unix.MismatchedDeallocator -analyzer-eagerly-assume -analyzer-config path-diagnostics-alternate=true -analyzer-output=plist -o %t -w %s
// RUN: FileCheck --input-file %t %s
//===----------------------------------------------------------------------===//
@@ -230,7 +230,7 @@ void test_do_while() {
p = 0;
} while (i< 2);
-
+
*p = 0xDEADBEEF;
}
diff --git a/test/Analysis/elementtype.c b/test/Analysis/elementtype.c
index 1b2681181b40..7eba8e14b3a7 100644
--- a/test/Analysis/elementtype.c
+++ b/test/Analysis/elementtype.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region %s
typedef struct added_obj_st {
int type;
diff --git a/test/Analysis/engine/replay-without-inlining.c b/test/Analysis/engine/replay-without-inlining.c
index 14b2b819b9e6..0b9820eba698 100644
--- a/test/Analysis/engine/replay-without-inlining.c
+++ b/test/Analysis/engine/replay-without-inlining.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify %s
// expected-no-diagnostics
typedef struct {
diff --git a/test/Analysis/enum.cpp b/test/Analysis/enum.cpp
index 571fa7ba228d..e26b8f00d98c 100644
--- a/test/Analysis/enum.cpp
+++ b/test/Analysis/enum.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=debug.ExprInspection %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=debug.ExprInspection %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/exceptions.mm b/test/Analysis/exceptions.mm
index dab1b5e8c9c8..0e776373b62a 100644
--- a/test/Analysis/exceptions.mm
+++ b/test/Analysis/exceptions.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -fexceptions -fobjc-exceptions -fcxx-exceptions -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -fexceptions -fobjc-exceptions -fcxx-exceptions -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
void clang_analyzer_checkInlined(bool);
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index 03b6874b68ee..577b88bf837f 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
//
// Just exercise the analyzer on code that has at one point caused issues
// (i.e., no assertions or crashes).
diff --git a/test/Analysis/explain-svals.c b/test/Analysis/explain-svals.c
new file mode 100644
index 000000000000..f1540bbe2de8
--- /dev/null
+++ b/test/Analysis/explain-svals.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection,unix.cstring -verify %s
+
+struct S {
+ int z;
+};
+
+void clang_analyzer_explain_int(int);
+void clang_analyzer_explain_voidp(void *);
+void clang_analyzer_explain_S(struct S);
+
+int glob;
+
+void test_1(int param, void *ptr) {
+ clang_analyzer_explain_voidp(&glob); // expected-warning-re{{{{^pointer to global variable 'glob'$}}}}
+ clang_analyzer_explain_int(param); // expected-warning-re{{{{^argument 'param'$}}}}
+ clang_analyzer_explain_voidp(ptr); // expected-warning-re{{{{^argument 'ptr'$}}}}
+ if (param == 42)
+ clang_analyzer_explain_int(param); // expected-warning-re{{{{^signed 32-bit integer '42'$}}}}
+}
+
+void test_2(struct S s) {
+ clang_analyzer_explain_S(s); //expected-warning-re{{{{^lazily frozen compound value of parameter 's'$}}}}
+ clang_analyzer_explain_voidp(&s); // expected-warning-re{{{{^pointer to parameter 's'$}}}}
+ clang_analyzer_explain_int(s.z); // expected-warning-re{{{{^initial value of field 'z' of parameter 's'$}}}}
+}
diff --git a/test/Analysis/explain-svals.cpp b/test/Analysis/explain-svals.cpp
index be2f83037051..d4b56a348252 100644
--- a/test/Analysis/explain-svals.cpp
+++ b/test/Analysis/explain-svals.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection,unix.cstring -verify %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core.builtin,debug.ExprInspection,unix.cstring -verify %s
typedef unsigned long size_t;
diff --git a/test/Analysis/explain-svals.m b/test/Analysis/explain-svals.m
index 34cdacfa282c..dd40946c8432 100644
--- a/test/Analysis/explain-svals.m
+++ b/test/Analysis/explain-svals.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -w -triple i386-apple-darwin10 -fblocks -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -w -triple i386-apple-darwin10 -fblocks -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
#include "Inputs/system-header-simulator-objc.h"
diff --git a/test/Analysis/expr-inspection.c b/test/Analysis/expr-inspection.c
index 69e18cb1e686..59406cd420ad 100644
--- a/test/Analysis/expr-inspection.c
+++ b/test/Analysis/expr-inspection.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection -verify %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s 2>&1 | FileCheck %s
// Self-tests for the debug.ExprInspection checker.
@@ -19,4 +19,4 @@ void foo(int x) {
// CHECK: Expressions:
// CHECK-NEXT: clang_analyzer_printState : &code{clang_analyzer_printState}
-// CHECK-NEXT: Ranges are empty.
+// CHECK-NEXT: {{(Ranges are empty.)|(Constraints:[[:space:]]*$)}}
diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c
index a670c50434e3..1aa484074208 100644
--- a/test/Analysis/fields.c
+++ b/test/Analysis/fields.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection %s -analyzer-store=region -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection %s -analyzer-store=region -verify
void clang_analyzer_eval(int);
diff --git a/test/Analysis/free.c b/test/Analysis/free.c
index 3746bf11c04e..acdb2820d328 100644
--- a/test/Analysis/free.c
+++ b/test/Analysis/free.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify -analyzer-config unix.Malloc:Optimistic=true %s
+// RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify -analyzer-config unix.Malloc:Optimistic=true %s
typedef __typeof(sizeof(int)) size_t;
void free(void *);
void *alloca(size_t);
diff --git a/test/Analysis/func.c b/test/Analysis/func.c
index 78afb45da696..58d4f45eeb50 100644
--- a/test/Analysis/func.c
+++ b/test/Analysis/func.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
void clang_analyzer_eval(int);
void clang_analyzer_warnIfReached();
diff --git a/test/Analysis/generics.m b/test/Analysis/generics.m
index da5c5126566c..dac148d42e8e 100644
--- a/test/Analysis/generics.m
+++ b/test/Analysis/generics.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.ObjCGenerics,alpha.core.DynamicTypeChecker -verify -Wno-objc-method-access %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.ObjCGenerics,alpha.core.DynamicTypeChecker -verify -Wno-objc-method-access %s -analyzer-output=plist -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.ObjCGenerics,alpha.core.DynamicTypeChecker -verify -Wno-objc-method-access %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.ObjCGenerics,alpha.core.DynamicTypeChecker -verify -Wno-objc-method-access %s -analyzer-output=plist -o %t.plist
// RUN: FileCheck --input-file %t.plist %s
#if !__has_feature(objc_generics)
diff --git a/test/Analysis/global-region-invalidation.c b/test/Analysis/global-region-invalidation.c
index bff22012c0c7..83df292f5885 100644
--- a/test/Analysis/global-region-invalidation.c
+++ b/test/Analysis/global-region-invalidation.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,alpha.security.taint,debug.TaintTest,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,alpha.security.taint,debug.TaintTest,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/global_region_invalidation.mm b/test/Analysis/global_region_invalidation.mm
index 2369c09d22f1..aee3b66a63d3 100644
--- a/test/Analysis/global_region_invalidation.mm
+++ b/test/Analysis/global_region_invalidation.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/gmalloc.c b/test/Analysis/gmalloc.c
new file mode 100644
index 000000000000..10c4fe284054
--- /dev/null
+++ b/test/Analysis/gmalloc.c
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify %s
+
+#include "Inputs/system-header-simulator.h"
+
+typedef void* gpointer;
+typedef const void* gconstpointer;
+typedef unsigned long gsize;
+typedef unsigned int guint;
+
+gpointer g_malloc(gsize n_bytes);
+gpointer g_malloc0(gsize n_bytes);
+gpointer g_realloc(gpointer mem, gsize n_bytes);
+gpointer g_try_malloc(gsize n_bytes);
+gpointer g_try_malloc0(gsize n_bytes);
+gpointer g_try_realloc(gpointer mem, gsize n_bytes);
+void g_free(gpointer mem);
+gpointer g_memdup(gconstpointer mem, guint byte_size);
+
+static const gsize n_bytes = 1024;
+
+void f1() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+
+ g_free(g1);
+ g_free(g2);
+ g_free(g2); // expected-warning{{Attempt to free released memory}}
+}
+
+void f2() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+
+ g_free(g1);
+ g_free(g2);
+ g_free(g3);
+ g3 = g_memdup(g3, n_bytes); // expected-warning{{Use of memory after it is freed}}
+}
+
+void f3() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2); // expected-warning{{Potential leak of memory pointed to by 'g4'}}
+
+ g_free(g1);
+ g_free(g2);
+ g_free(g3);
+}
diff --git a/test/Analysis/gtest.cpp b/test/Analysis/gtest.cpp
index f33569598e1e..5797a773b423 100644
--- a/test/Analysis/gtest.cpp
+++ b/test/Analysis/gtest.cpp
@@ -1,6 +1,6 @@
-//RUN: %clang_cc1 -cc1 -std=c++11 -analyze -analyzer-checker=core,apiModeling.google.GTest,debug.ExprInspection -analyzer-eagerly-assume %s -verify
-//RUN: %clang_cc1 -cc1 -std=c++11 -analyze -analyzer-checker=core,apiModeling.google.GTest,debug.ExprInspection -analyzer-eagerly-assume -DGTEST_VERSION_1_8_AND_LATER=1 %s -verify
-//RUN: %clang_cc1 -cc1 -std=c++11 -analyze -analyzer-checker=core,apiModeling.google.GTest,debug.ExprInspection -analyzer-eagerly-assume -analyzer-config cfg-temporary-dtors=true %s -verify
+//RUN: %clang_analyze_cc1 -cc1 -std=c++11 -analyzer-checker=core,apiModeling.google.GTest,debug.ExprInspection -analyzer-eagerly-assume %s -verify
+//RUN: %clang_analyze_cc1 -cc1 -std=c++11 -analyzer-checker=core,apiModeling.google.GTest,debug.ExprInspection -analyzer-eagerly-assume -DGTEST_VERSION_1_8_AND_LATER=1 %s -verify
+//RUN: %clang_analyze_cc1 -cc1 -std=c++11 -analyzer-checker=core,apiModeling.google.GTest,debug.ExprInspection -analyzer-eagerly-assume -analyzer-config cfg-temporary-dtors=true %s -verify
void clang_analyzer_eval(int);
void clang_analyzer_warnIfReached();
diff --git a/test/Analysis/html-diags-multifile.c b/test/Analysis/html-diags-multifile.c
index bb769283bba9..ce1f72b6bb1a 100644
--- a/test/Analysis/html-diags-multifile.c
+++ b/test/Analysis/html-diags-multifile.c
@@ -1,5 +1,5 @@
// RUN: mkdir -p %t.dir
-// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t.dir %s
+// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %t.dir %s
// RUN: ls %t.dir | not grep report
// RUN: rm -fR %t.dir
diff --git a/test/Analysis/html-diags.c b/test/Analysis/html-diags.c
index e998020f4cfa..182bcfbdfa12 100644
--- a/test/Analysis/html-diags.c
+++ b/test/Analysis/html-diags.c
@@ -1,11 +1,11 @@
// RUN: rm -fR %T/dir
// RUN: mkdir %T/dir
-// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %T/dir %s
+// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %T/dir %s
// RUN: ls %T/dir | grep report
// PR16547: Test relative paths
// RUN: cd %T/dir
-// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o testrelative %s
+// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o testrelative %s
// RUN: ls %T/dir/testrelative | grep report
// Currently this test mainly checks that the HTML diagnostics doesn't crash
diff --git a/test/Analysis/identical-expressions.cpp b/test/Analysis/identical-expressions.cpp
index 138cd7ce9887..8bb82372b534 100644
--- a/test/Analysis/identical-expressions.cpp
+++ b/test/Analysis/identical-expressions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.IdenticalExpr -w -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.IdenticalExpr -w -verify %s
/* Only one expected warning per function allowed at the very end. */
diff --git a/test/Analysis/index-type.c b/test/Analysis/index-type.c
index fc638dfe7417..b86913b996f6 100644
--- a/test/Analysis/index-type.c
+++ b/test/Analysis/index-type.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,alpha.security.ArrayBoundV2 -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,alpha.security.ArrayBoundV2 -DM32 -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.security.ArrayBoundV2 -verify %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,alpha.security.ArrayBoundV2 -DM32 -verify %s
// expected-no-diagnostics
#define UINT_MAX (~0u)
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index 09509271dae0..c73635686d83 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/initializers-cfg-output.cpp b/test/Analysis/initializers-cfg-output.cpp
index deefbef07738..ccf4db519d79 100644
--- a/test/Analysis/initializers-cfg-output.cpp
+++ b/test/Analysis/initializers-cfg-output.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
class A {
public:
diff --git a/test/Analysis/inline-not-supported.c b/test/Analysis/inline-not-supported.c
index 756d5d8b8dbf..c5f4c74952cc 100644
--- a/test/Analysis/inline-not-supported.c
+++ b/test/Analysis/inline-not-supported.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core -verify %s
// For now, don't inline varargs.
void foo(int *x, ...) {
diff --git a/test/Analysis/inline-plist.c b/test/Analysis/inline-plist.c
index bccf219d31e5..441bb48b1055 100644
--- a/test/Analysis/inline-plist.c
+++ b/test/Analysis/inline-plist.c
@@ -1,5 +1,5 @@
-// RUN: %clang --analyze %s -fblocks -Xanalyzer -analyzer-output=text -Xanalyzer -analyzer-config -Xanalyzer suppress-null-return-paths=false -Xclang -verify %s
-// RUN: %clang --analyze %s -fblocks -Xanalyzer -analyzer-config -Xanalyzer suppress-null-return-paths=false -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -o %t
+// RUN: %clang_analyze_cc1 %s -analyzer-checker=core.NullDereference,core.DivideZero -fblocks -analyzer-output=text -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_analyze_cc1 %s -analyzer-checker=core.NullDereference,core.DivideZero -fblocks -analyzer-output=plist -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false -o %t
// RUN: FileCheck -input-file %t %s
// <rdar://problem/10967815>
@@ -41,7 +41,7 @@ void bar(int *p) {
// expected-note@-2 {{Taking false branch}}
return;
}
-
+
if (p == 0) {
// expected-note@-1 {{Taking true branch}}
triggers_bug(p);
@@ -59,7 +59,7 @@ void test_block__capture_null() {
^(){ // expected-note {{Calling anonymous block}}
*p = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} expected-note{{Dereference of null pointer (loaded from variable 'p')}}
}();
-
+
}
void test_block_ret() {
@@ -550,12 +550,12 @@ void test_block_arg() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>39</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>39</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -567,7 +567,7 @@ void test_block_arg() {
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>39</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <key>ranges</key>
@@ -575,7 +575,7 @@ void test_block_arg() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>39</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
@@ -600,12 +600,12 @@ void test_block_arg() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>39</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>39</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/inline-unique-reports.c b/test/Analysis/inline-unique-reports.c
index 4b3c2fecca1e..f827f88deb1d 100644
--- a/test/Analysis/inline-unique-reports.c
+++ b/test/Analysis/inline-unique-reports.c
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze %s -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -o %t > /dev/null 2>&1
+// RUN: %clang_analyze_cc1 %s -analyzer-checker=core.NullDereference -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t > /dev/null 2>&1
// RUN: FileCheck -input-file %t %s
static inline bug(int *p) {
diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c
index 03c4ea832581..8fce0fb176ea 100644
--- a/test/Analysis/inline.c
+++ b/test/Analysis/inline.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
void clang_analyzer_checkInlined(int);
diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp
index 9fc4f81c05b6..76eee5beffac 100644
--- a/test/Analysis/inline.cpp
+++ b/test/Analysis/inline.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -analyzer-config c++-allocator-inlining=true -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -analyzer-config c++-allocator-inlining=true -verify %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
diff --git a/test/Analysis/inline2.c b/test/Analysis/inline2.c
index bae7434518e2..39e6d16cc4fd 100644
--- a/test/Analysis/inline2.c
+++ b/test/Analysis/inline2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
// expected-no-diagnostics
// Test parameter 'a' is registered to LiveVariables analysis data although it
diff --git a/test/Analysis/inline3.c b/test/Analysis/inline3.c
index e7f4775925a1..2c70fb21aa2b 100644
--- a/test/Analysis/inline3.c
+++ b/test/Analysis/inline3.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
// expected-no-diagnostics
// Test when entering f1(), we set the right AnalysisDeclContext to Environment.
diff --git a/test/Analysis/inline4.c b/test/Analysis/inline4.c
index 71a379a02c75..a1aac1dec686 100644
--- a/test/Analysis/inline4.c
+++ b/test/Analysis/inline4.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
// expected-no-diagnostics
int g(int a) {
diff --git a/test/Analysis/inlining/DynDispatchBifurcate.m b/test/Analysis/inlining/DynDispatchBifurcate.m
index 0ce079654e98..a41a5e3a858d 100644
--- a/test/Analysis/inlining/DynDispatchBifurcate.m
+++ b/test/Analysis/inlining/DynDispatchBifurcate.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-config ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-config ipa=dynamic-bifurcate -verify %s
#include "InlineObjCInstanceMethod.h"
diff --git a/test/Analysis/inlining/InlineObjCClassMethod.m b/test/Analysis/inlining/InlineObjCClassMethod.m
index c9cc90ba27c0..bb869c5e5297 100644
--- a/test/Analysis/inlining/InlineObjCClassMethod.m
+++ b/test/Analysis/inlining/InlineObjCClassMethod.m
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
void clang_analyzer_checkInlined(int);
+void clang_analyzer_eval(int);
// Test inlining of ObjC class methods.
@@ -194,7 +195,9 @@ int foo2() {
@implementation SelfUsedInParent
+ (int)getNum {return 5;}
+ (int)foo {
- return [self getNum];
+ int r = [self getNum];
+ clang_analyzer_eval(r == 5); // expected-warning{{TRUE}}
+ return r;
}
@end
@interface SelfUsedInParentChild : SelfUsedInParent
@@ -229,8 +232,80 @@ void rdar15037033() {
+ (void)forwardDeclaredVariadicMethod:(int)x, ... {
clang_analyzer_checkInlined(0); // no-warning
}
+@end
+@interface SelfClassTestParent : NSObject
+-(unsigned)returns10;
++(unsigned)returns20;
++(unsigned)returns30;
@end
+@implementation SelfClassTestParent
+-(unsigned)returns10 { return 100; }
++(unsigned)returns20 { return 100; }
++(unsigned)returns30 { return 100; }
+@end
+@interface SelfClassTest : SelfClassTestParent
+-(unsigned)returns10;
++(unsigned)returns20;
++(unsigned)returns30;
+@end
+
+@implementation SelfClassTest
+-(unsigned)returns10 { return 10; }
++(unsigned)returns20 { return 20; }
++(unsigned)returns30 { return 30; }
++(void)classMethod {
+ unsigned result1 = [self returns20];
+ clang_analyzer_eval(result1 == 20); // expected-warning{{TRUE}}
+ unsigned result2 = [[self class] returns30];
+ clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}
+ unsigned result3 = [[super class] returns30];
+ clang_analyzer_eval(result3 == 100); // expected-warning{{UNKNOWN}}
+}
+-(void)instanceMethod {
+ unsigned result0 = [self returns10];
+ clang_analyzer_eval(result0 == 10); // expected-warning{{TRUE}}
+ unsigned result2 = [[self class] returns30];
+ clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}
+ unsigned result3 = [[super class] returns30];
+ clang_analyzer_eval(result3 == 100); // expected-warning{{UNKNOWN}}
+}
+@end
+@interface Parent : NSObject
++ (int)a;
++ (int)b;
+@end
+@interface Child : Parent
+@end
+@interface Other : NSObject
++(void)run;
+@end
+int main(int argc, const char * argv[]) {
+ @autoreleasepool {
+ [Other run];
+ }
+ return 0;
+}
+@implementation Other
++(void)run {
+ int result = [Child a];
+ // TODO: This should return 100.
+ clang_analyzer_eval(result == 12); // expected-warning{{TRUE}}
+}
+@end
+@implementation Parent
++ (int)a; {
+ return [self b];
+}
++ (int)b; {
+ return 12;
+}
+@end
+@implementation Child
++ (int)b; {
+ return 100;
+}
+@end
diff --git a/test/Analysis/inlining/InlineObjCInstanceMethod.m b/test/Analysis/inlining/InlineObjCInstanceMethod.m
index f6aa50a24802..4578a55c7a07 100644
--- a/test/Analysis/inlining/InlineObjCInstanceMethod.m
+++ b/test/Analysis/inlining/InlineObjCInstanceMethod.m
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze -Xanalyzer -analyzer-checker=osx.cocoa.IncompatibleMethodTypes,osx.coreFoundation.CFRetainRelease -Xclang -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero,core.DynamicTypePropagation,osx.cocoa.IncompatibleMethodTypes -w -verify %s
#include "InlineObjCInstanceMethod.h"
diff --git a/test/Analysis/inlining/ObjCDynTypePopagation.m b/test/Analysis/inlining/ObjCDynTypePopagation.m
index ccc24713782a..0c1d4f2a31cb 100644
--- a/test/Analysis/inlining/ObjCDynTypePopagation.m
+++ b/test/Analysis/inlining/ObjCDynTypePopagation.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
#include "InlineObjCInstanceMethod.h"
diff --git a/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m b/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
index 06b271ad4b36..d787c7e9e17b 100644
--- a/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
+++ b/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
diff --git a/test/Analysis/inlining/RetainCountExamples.m b/test/Analysis/inlining/RetainCountExamples.m
index 41479af0a096..938d3e2bfb62 100644
--- a/test/Analysis/inlining/RetainCountExamples.m
+++ b/test/Analysis/inlining/RetainCountExamples.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config ipa=dynamic-bifurcate -verify %s
typedef signed char BOOL;
typedef struct objc_class *Class;
diff --git a/test/Analysis/inlining/analysis-order.c b/test/Analysis/inlining/analysis-order.c
index 5149818c74fd..620732c68542 100644
--- a/test/Analysis/inlining/analysis-order.c
+++ b/test/Analysis/inlining/analysis-order.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.builtin.NoReturnFunctions -analyzer-display-progress %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.builtin.NoReturnFunctions -analyzer-display-progress %s 2>&1 | FileCheck %s
// Do not analyze test1() again because it was inlined
void test1();
diff --git a/test/Analysis/inlining/assume-super-init-does-not-return-nil.m b/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
index fba3e2d1b54b..be46776b37d4 100644
--- a/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
+++ b/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -verify %s
typedef signed char BOOL;
diff --git a/test/Analysis/inlining/containers.cpp b/test/Analysis/inlining/containers.cpp
index c757da66bedb..16e006b345f2 100644
--- a/test/Analysis/inlining/containers.cpp
+++ b/test/Analysis/inlining/containers.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=false -verify %s
-// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=true -DINLINE=1 -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=false -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=true -DINLINE=1 -verify %s
#ifndef HEADER
diff --git a/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp b/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
index e23d4e23a48f..02084839c55b 100644
--- a/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
+++ b/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify -Wno-reinterpret-base-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify -Wno-reinterpret-base-class %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.c b/test/Analysis/inlining/eager-reclamation-path-notes.c
index cd16eb3af930..7c0f0ec8f52e 100644
--- a/test/Analysis/inlining/eager-reclamation-path-notes.c
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config graph-trim-interval=5 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -analyzer-config graph-trim-interval=5 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void use(int *ptr, int val) {
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.cpp b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
index 8d5e85a6394f..f77a19f9965f 100644
--- a/test/Analysis/inlining/eager-reclamation-path-notes.cpp
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
typedef struct {
diff --git a/test/Analysis/inlining/false-positive-suppression.c b/test/Analysis/inlining/false-positive-suppression.c
index a0bc3611fe97..4931695ef127 100644
--- a/test/Analysis/inlining/false-positive-suppression.c
+++ b/test/Analysis/inlining/false-positive-suppression.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -verify -DSUPPRESSED=1 %s
-// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-eagerly-assume -analyzer-checker=core -verify -DSUPPRESSED=1 %s
+// RUN: %clang_analyze_cc1 -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
int opaquePropertyCheck(void *object);
int coin();
diff --git a/test/Analysis/inlining/false-positive-suppression.cpp b/test/Analysis/inlining/false-positive-suppression.cpp
index bff6907809c1..56659b4a1941 100644
--- a/test/Analysis/inlining/false-positive-suppression.cpp
+++ b/test/Analysis/inlining/false-positive-suppression.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED=1 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -DSUPPRESSED=1 %s
namespace rdar12676053 {
// Delta-reduced from a preprocessed file.
diff --git a/test/Analysis/inlining/false-positive-suppression.m b/test/Analysis/inlining/false-positive-suppression.m
index 685e29e23131..f3532e5d6640 100644
--- a/test/Analysis/inlining/false-positive-suppression.m
+++ b/test/Analysis/inlining/false-positive-suppression.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED=1 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -fobjc-arc -verify -DSUPPRESSED=1 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -DSUPPRESSED=1 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -fobjc-arc -verify -DSUPPRESSED=1 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
#define ARC __has_feature(objc_arc)
diff --git a/test/Analysis/inlining/inline-defensive-checks.c b/test/Analysis/inlining/inline-defensive-checks.c
index 4ce783c852fe..4029da651b65 100644
--- a/test/Analysis/inlining/inline-defensive-checks.c
+++ b/test/Analysis/inlining/inline-defensive-checks.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
// Perform inline defensive checks.
void idc(int *p) {
diff --git a/test/Analysis/inlining/inline-defensive-checks.cpp b/test/Analysis/inlining/inline-defensive-checks.cpp
index b69c53565784..6a803fa695c6 100644
--- a/test/Analysis/inlining/inline-defensive-checks.cpp
+++ b/test/Analysis/inlining/inline-defensive-checks.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
// expected-no-diagnostics
extern void __assert_fail (__const char *__assertion, __const char *__file,
diff --git a/test/Analysis/inlining/inline-defensive-checks.m b/test/Analysis/inlining/inline-defensive-checks.m
index 0404ee6df813..38e5446ecd39 100644
--- a/test/Analysis/inlining/inline-defensive-checks.m
+++ b/test/Analysis/inlining/inline-defensive-checks.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
typedef signed char BOOL;
typedef struct objc_class *Class;
diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c
index 403d33db4851..95adee30a9af 100644
--- a/test/Analysis/inlining/path-notes.c
+++ b/test/Analysis/inlining/path-notes.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void zero(int **p) {
diff --git a/test/Analysis/inlining/path-notes.cpp b/test/Analysis/inlining/path-notes.cpp
index 2d6886f9a77f..4d0b899e7cf7 100644
--- a/test/Analysis/inlining/path-notes.cpp
+++ b/test/Analysis/inlining/path-notes.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config c++-inlining=destructors -std=c++11 -verify -Wno-tautological-undefined-compare %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 -analyzer-config path-diagnostics-alternate=false %s -o %t.plist -Wno-tautological-undefined-compare
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -analyzer-config c++-inlining=destructors -std=c++11 -verify -Wno-tautological-undefined-compare %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 -analyzer-config path-diagnostics-alternate=false %s -o %t.plist -Wno-tautological-undefined-compare
// RUN: FileCheck --input-file=%t.plist %s
class Foo {
diff --git a/test/Analysis/inlining/path-notes.m b/test/Analysis/inlining/path-notes.m
index d9b5a5820fe5..7f60ff8e3200 100644
--- a/test/Analysis/inlining/path-notes.m
+++ b/test/Analysis/inlining/path-notes.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false -fblocks %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -analyzer-config path-diagnostics-alternate=false -fblocks %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
typedef struct dispatch_queue_s *dispatch_queue_t;
diff --git a/test/Analysis/inlining/retain-count-self-init.m b/test/Analysis/inlining/retain-count-self-init.m
index 97379dbc7a88..208197381f60 100644
--- a/test/Analysis/inlining/retain-count-self-init.m
+++ b/test/Analysis/inlining/retain-count-self-init.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.SelfInit -analyzer-config ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.SelfInit -analyzer-config ipa=dynamic-bifurcate -verify %s
typedef signed char BOOL;
typedef struct objc_class *Class;
diff --git a/test/Analysis/inlining/stl.cpp b/test/Analysis/inlining/stl.cpp
index d89a10983041..b672be2ba245 100644
--- a/test/Analysis/inlining/stl.cpp
+++ b/test/Analysis/inlining/stl.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -std=c++11 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -std=c++11 -DINLINE=1 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -std=c++11 -DINLINE=1 -verify %s
#include "../Inputs/system-header-simulator-cxx.h"
diff --git a/test/Analysis/inlining/test-always-inline-size-option.c b/test/Analysis/inlining/test-always-inline-size-option.c
index 6b3c13d2b672..85fc8a16cc75 100644
--- a/test/Analysis/inlining/test-always-inline-size-option.c
+++ b/test/Analysis/inlining/test-always-inline-size-option.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-inline-max-stack-depth=3 -analyzer-config ipa-always-inline-size=3 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-inline-max-stack-depth=3 -analyzer-config ipa-always-inline-size=3 -verify %s
void clang_analyzer_eval(int);
int nested5() {
diff --git a/test/Analysis/inlining/test_objc_inlining_option.m b/test/Analysis/inlining/test_objc_inlining_option.m
index 61408c1f3d42..f3a9417dac31 100644
--- a/test/Analysis/inlining/test_objc_inlining_option.m
+++ b/test/Analysis/inlining/test_objc_inlining_option.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config ipa=dynamic-bifurcate -analyzer-config objc-inlining=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config ipa=dynamic-bifurcate -analyzer-config objc-inlining=false -verify %s
// expected-no-diagnostics
typedef signed char BOOL;
diff --git a/test/Analysis/iterator-past-end.cpp b/test/Analysis/iterator-past-end.cpp
index 4d9ed0cf9816..252d1044bd16 100644
--- a/test/Analysis/iterator-past-end.cpp
+++ b/test/Analysis/iterator-past-end.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorPastEnd -analyzer-eagerly-assume -analyzer-config c++-container-inlining=false %s -verify
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorPastEnd -analyzer-eagerly-assume -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorPastEnd -analyzer-eagerly-assume -analyzer-config c++-container-inlining=false %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorPastEnd -analyzer-eagerly-assume -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
#include "Inputs/system-header-simulator-cxx.h"
diff --git a/test/Analysis/ivars.m b/test/Analysis/ivars.m
index c717da63ee61..11514d2f8309 100644
--- a/test/Analysis/ivars.m
+++ b/test/Analysis/ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/keychainAPI-diagnostic-visitor.m b/test/Analysis/keychainAPI-diagnostic-visitor.m
index a78b114a00fb..d8da697a41e8 100644
--- a/test/Analysis/keychainAPI-diagnostic-visitor.m
+++ b/test/Analysis/keychainAPI-diagnostic-visitor.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=osx.SecKeychainAPI -analyzer-store=region -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=osx.SecKeychainAPI -analyzer-store=region -analyzer-output=text -verify %s
// This file is for testing enhanced diagnostics produced by the default SecKeychainAPI checker.
diff --git a/test/Analysis/keychainAPI.m b/test/Analysis/keychainAPI.m
index 4fc48c066f9d..1725ce15f0e6 100644
--- a/test/Analysis/keychainAPI.m
+++ b/test/Analysis/keychainAPI.m
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.SecKeychainAPI -fblocks %s -verify
+
+#include "Inputs/system-header-simulator-objc.h"
// Fake typedefs.
typedef unsigned int OSStatus;
@@ -6,8 +8,6 @@ typedef unsigned int SecKeychainAttributeList;
typedef unsigned int SecKeychainItemRef;
typedef unsigned int SecItemClass;
typedef unsigned int UInt32;
-typedef unsigned int CFTypeRef;
-typedef unsigned int UInt16;
typedef unsigned int SecProtocolType;
typedef unsigned int SecAuthenticationType;
typedef unsigned int SecKeychainAttributeInfo;
@@ -77,7 +77,7 @@ void errRetVal() {
void *outData;
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
if (st == GenericError)
- SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Only call free if a valid (non-NULL) buffer was returned}}
+ SecKeychainItemFreeContent(ptr, outData);
} // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}
// If null is passed in, the data is not allocated, so no need for the matching free.
@@ -101,14 +101,6 @@ void doubleAlloc() {
SecKeychainItemFreeContent(ptr, outData);
}
-void fooOnlyFree() {
- unsigned int *ptr = 0;
- OSStatus st = 0;
- UInt32 length;
- void *outData = &length;
- SecKeychainItemFreeContent(ptr, outData);// expected-warning{{Trying to free data which has not been allocated}}
-}
-
// Do not warn if undefined value is passed to a function.
void fooOnlyFreeUndef() {
unsigned int *ptr = 0;
@@ -220,11 +212,27 @@ int foo(CFTypeRef keychainOrArray, SecProtocolType protocol,
if (st == noErr)
SecKeychainItemFreeContent(ptr, outData[3]);
}
- if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}
+ if (length) { // TODO: We do not report a warning here since the symbol is no longer live, but it's not marked as dead.
length++;
}
return 0;
-}// no-warning
+}
+
+int testErrorCodeAsLHS(CFTypeRef keychainOrArray, SecProtocolType protocol,
+ SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData;
+ st = SecKeychainFindInternetPassword(keychainOrArray,
+ 16, "server", 16, "domain", 16, "account",
+ 16, "path", 222, protocol, authenticationType,
+ &length, &outData, itemRef);
+ if (noErr == st)
+ SecKeychainItemFreeContent(ptr, outData);
+
+ return 0;
+}
void free(void *ptr);
void deallocateWithFree() {
@@ -251,7 +259,6 @@ extern const CFAllocatorRef kCFAllocatorMallocZone;
extern const CFAllocatorRef kCFAllocatorNull;
extern const CFAllocatorRef kCFAllocatorUseContext;
CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator);
-extern void CFRelease(CFStringRef cf);
void DellocWithCFStringCreate1(CFAllocatorRef alloc) {
unsigned int *ptr = 0;
@@ -333,11 +340,11 @@ void radar10508828() {
SecKeychainItemFreeContent(0, pwdBytes);
}
-void radar10508828_2() {
+void radar10508828_20092614() {
UInt32 pwdLen = 0;
void* pwdBytes = 0;
OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);
- SecKeychainItemFreeContent(0, pwdBytes); // expected-warning {{Only call free if a valid (non-NULL) buffer was returned}}
+ SecKeychainItemFreeContent(0, pwdBytes);
}
//Example from bug 10797.
@@ -426,3 +433,24 @@ void allocAndFree3(void *attrList) {
SecKeychainItemFreeContent(attrList, outData);
}
+typedef struct AuthorizationValue {
+ int length;
+ void *data;
+} AuthorizationValue;
+typedef struct AuthorizationCallback {
+ OSStatus (*SetContextVal)(AuthorizationValue *inValue);
+} AuthorizationCallback;
+static AuthorizationCallback cb;
+int radar_19196494() {
+ @autoreleasepool {
+ AuthorizationValue login_password = {};
+ UInt32 passwordLength;
+ void *passwordData = 0;
+ OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0);
+ cb.SetContextVal(&login_password);
+ if (err == noErr) {
+ SecKeychainItemFreeContent(0, login_password.data);
+ }
+ }
+ return 0;
+}
diff --git a/test/Analysis/kmalloc-linux.c b/test/Analysis/kmalloc-linux.c
index 87c1107a102e..bac71388a7a8 100644
--- a/test/Analysis/kmalloc-linux.c
+++ b/test/Analysis/kmalloc-linux.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target x86_64-unknown-linux --analyze %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux %s
#include "Inputs/system-header-simulator.h"
diff --git a/test/Analysis/lambda-notes.cpp b/test/Analysis/lambda-notes.cpp
index 661fd052c87d..7abff35df124 100644
--- a/test/Analysis/lambda-notes.cpp
+++ b/test/Analysis/lambda-notes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core -analyzer-config inline-lambdas=true -analyzer-output plist -verify %s -o %t
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core.DivideZero -analyzer-config inline-lambdas=true -analyzer-output plist -verify %s -o %t
// RUN: FileCheck --input-file=%t %s
diff --git a/test/Analysis/lambdas-generalized-capture.cpp b/test/Analysis/lambdas-generalized-capture.cpp
index 790e15e8ccc3..feaf55d6c84e 100644
--- a/test/Analysis/lambdas-generalized-capture.cpp
+++ b/test/Analysis/lambdas-generalized-capture.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++14 -fsyntax-only -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core,deadcode,debug.ExprInspection -verify %s
int clang_analyzer_eval(int);
diff --git a/test/Analysis/lambdas.cpp b/test/Analysis/lambdas.cpp
index 0b66e6b92fa6..f3ff9b953938 100644
--- a/test/Analysis/lambdas.cpp
+++ b/test/Analysis/lambdas.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
void clang_analyzer_warnIfReached();
@@ -212,7 +212,7 @@ struct DontCrash {
callLambda([&](){ ++x; });
callLambdaFromStatic([&](){ ++x; });
}
-
+
template<typename T>
static void callLambdaFromStatic(T t) {
t();
diff --git a/test/Analysis/lambdas.mm b/test/Analysis/lambdas.mm
index dc1a13e8b69d..d2b8e7b35356 100644
--- a/test/Analysis/lambdas.mm
+++ b/test/Analysis/lambdas.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fblocks -Wno-objc-root-class -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -Wno-objc-root-class -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
int clang_analyzer_eval(int);
diff --git a/test/Analysis/lifetime-extension.cpp b/test/Analysis/lifetime-extension.cpp
index 124eef32fde3..5e3c5dde0a8b 100644
--- a/test/Analysis/lifetime-extension.cpp
+++ b/test/Analysis/lifetime-extension.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-unused -std=c++11 -analyze -analyzer-checker=debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/lit.local.cfg b/test/Analysis/lit.local.cfg
index da2a68b378cc..a594c5dada58 100644
--- a/test/Analysis/lit.local.cfg
+++ b/test/Analysis/lit.local.cfg
@@ -1,2 +1,13 @@
-if config.root.clang_staticanalyzer == 0:
+# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
+
+import site
+
+# Load the custom analyzer test format, which runs the test again with Z3 if it
+# is available.
+site.addsitedir(os.path.dirname(__file__))
+import analyzer_test
+config.test_format = analyzer_test.AnalyzerTest(
+ config.test_format.execute_external)
+
+if not config.root.clang_staticanalyzer:
config.unsupported = True
diff --git a/test/Analysis/live-variables.cpp b/test/Analysis/live-variables.cpp
index 0cfaa1b41f52..2c38b8bd7134 100644
--- a/test/Analysis/live-variables.cpp
+++ b/test/Analysis/live-variables.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
// expected-no-diagnostics
class B {
public:
diff --git a/test/Analysis/live-variables.m b/test/Analysis/live-variables.m
index eefd292bf79b..d2390f3f8787 100644
--- a/test/Analysis/live-variables.m
+++ b/test/Analysis/live-variables.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -fobjc-arc -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -fobjc-arc -verify %s
// expected-no-diagnostics
@interface NSObject
@end
diff --git a/test/Analysis/localization-aggressive.m b/test/Analysis/localization-aggressive.m
index 89950d4eed74..346cf3ef22e2 100644
--- a/test/Analysis/localization-aggressive.m
+++ b/test/Analysis/localization-aggressive.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fblocks -x objective-c-header -emit-pch -o %t.pch %S/Inputs/localization-pch.h
-// RUN: %clang_cc1 -analyze -fblocks -analyzer-store=region -analyzer-checker=optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker=optin.osx.cocoa.localizability.EmptyLocalizationContextChecker -include-pch %t.pch -verify -analyzer-config AggressiveReport=true %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-store=region -analyzer-checker=optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker=optin.osx.cocoa.localizability.EmptyLocalizationContextChecker -include-pch %t.pch -verify -analyzer-config AggressiveReport=true %s
// These declarations were reduced using Delta-Debugging from Foundation.h
// on Mac OS X.
diff --git a/test/Analysis/localization.m b/test/Analysis/localization.m
index 200eac3f037e..3a6a0d707373 100644
--- a/test/Analysis/localization.m
+++ b/test/Analysis/localization.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -fblocks -analyzer-store=region -analyzer-output=text -analyzer-checker=optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker=alpha.osx.cocoa.localizability.PluralMisuseChecker -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-store=region -analyzer-output=text -analyzer-checker=optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker=alpha.osx.cocoa.localizability.PluralMisuseChecker -verify %s
// The larger set of tests in located in localization.m. These are tests
// specific for non-aggressive reporting.
diff --git a/test/Analysis/logical-ops.c b/test/Analysis/logical-ops.c
index 0b63bc9ec835..553050173b02 100644
--- a/test/Analysis/logical-ops.c
+++ b/test/Analysis/logical-ops.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-pointer-bool-conversion -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -Wno-pointer-bool-conversion -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/loop-widening.c b/test/Analysis/loop-widening.c
index 0b9bf7080873..de17951d180f 100644
--- a/test/Analysis/loop-widening.c
+++ b/test/Analysis/loop-widening.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify %s
void clang_analyzer_eval(int);
void clang_analyzer_warnIfReached();
diff --git a/test/Analysis/lvalue.cpp b/test/Analysis/lvalue.cpp
index 9a6bd5939743..762113987663 100644
--- a/test/Analysis/lvalue.cpp
+++ b/test/Analysis/lvalue.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -verify %s
// expected-no-diagnostics
int f1() {
diff --git a/test/Analysis/malloc-annotations.c b/test/Analysis/malloc-annotations.c
index 3119cb7e9744..21eaab72b766 100644
--- a/test/Analysis/malloc-annotations.c
+++ b/test/Analysis/malloc-annotations.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc -analyzer-store=region -verify -analyzer-config unix.Malloc:Optimistic=true %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc -analyzer-store=region -verify -analyzer-config unix.Malloc:Optimistic=true %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
diff --git a/test/Analysis/malloc-custom.c b/test/Analysis/malloc-custom.c
index 3c16bbd17e68..f33b150de678 100644
--- a/test/Analysis/malloc-custom.c
+++ b/test/Analysis/malloc-custom.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -Wno-incompatible-library-redeclaration -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -Wno-incompatible-library-redeclaration -verify %s
// Various tests to make the the analyzer is robust against custom
// redeclarations of memory routines.
diff --git a/test/Analysis/malloc-interprocedural.c b/test/Analysis/malloc-interprocedural.c
index c78cc6c6aae4..4f7daec1b5bc 100644
--- a/test/Analysis/malloc-interprocedural.c
+++ b/test/Analysis/malloc-interprocedural.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-inline-max-stack-depth=5 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc -analyzer-inline-max-stack-depth=5 -verify %s
#include "Inputs/system-header-simulator.h"
diff --git a/test/Analysis/malloc-overflow.c b/test/Analysis/malloc-overflow.c
index 99e05adab6fb..d8ad062840d5 100644
--- a/test/Analysis/malloc-overflow.c
+++ b/test/Analysis/malloc-overflow.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.MallocOverflow -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.MallocOverflow -verify %s
#define NULL ((void *) 0)
typedef __typeof__(sizeof(int)) size_t;
diff --git a/test/Analysis/malloc-overflow.cpp b/test/Analysis/malloc-overflow.cpp
index e3a0408863e6..e070217cf7d8 100644
--- a/test/Analysis/malloc-overflow.cpp
+++ b/test/Analysis/malloc-overflow.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.MallocOverflow -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.MallocOverflow -verify %s
// expected-no-diagnostics
class A {
diff --git a/test/Analysis/malloc-overflow2.c b/test/Analysis/malloc-overflow2.c
index 83a2c02213b2..2e1b1d4d2b24 100644
--- a/test/Analysis/malloc-overflow2.c
+++ b/test/Analysis/malloc-overflow2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -analyze -analyzer-checker=alpha.security.MallocOverflow,unix -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -analyzer-checker=alpha.security.MallocOverflow,unix -verify %s
typedef __typeof__(sizeof(int)) size_t;
extern void *malloc(size_t);
diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c
index d6c4f39103fa..26aea1604517 100644
--- a/test/Analysis/malloc-plist.c
+++ b/test/Analysis/malloc-plist.c
@@ -1,5 +1,5 @@
// RUN: rm -f %t
-// RUN: %clang_cc1 -analyze -fblocks -analyzer-checker=core,unix.Malloc -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,unix.Malloc -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
// RUN: FileCheck -input-file %t %s
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/malloc-protoype.c b/test/Analysis/malloc-protoype.c
index f056f0f2855d..0b8c0f9f28df 100644
--- a/test/Analysis/malloc-protoype.c
+++ b/test/Analysis/malloc-protoype.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -w -analyze -analyzer-checker=core,unix.Malloc -verify %s
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core,unix.Malloc -verify %s
// expected-no-diagnostics
// Test that strange prototypes doesn't crash the analyzer
diff --git a/test/Analysis/malloc-sizeof.c b/test/Analysis/malloc-sizeof.c
index 7a8585fa8442..ee104245b819 100644
--- a/test/Analysis/malloc-sizeof.c
+++ b/test/Analysis/malloc-sizeof.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.MallocSizeof -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.MallocSizeof -verify %s
#include <stddef.h>
diff --git a/test/Analysis/malloc-sizeof.cpp b/test/Analysis/malloc-sizeof.cpp
index 8589975f8fc2..30227a9cbc80 100644
--- a/test/Analysis/malloc-sizeof.cpp
+++ b/test/Analysis/malloc-sizeof.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.MallocSizeof -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.MallocSizeof -verify %s
#include <stddef.h>
diff --git a/test/Analysis/malloc-three-arg.c b/test/Analysis/malloc-three-arg.c
index 01b08aeda51a..a2103376e348 100644
--- a/test/Analysis/malloc-three-arg.c
+++ b/test/Analysis/malloc-three-arg.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target x86_64-unknown-freebsd --analyze %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-freebsd %s
#include "Inputs/system-header-simulator.h"
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index d5bc6571e42a..d5f2cfedd185 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
#include "Inputs/system-header-simulator.h"
diff --git a/test/Analysis/malloc.cpp b/test/Analysis/malloc.cpp
index a8a79cac868b..c323754bb467 100644
--- a/test/Analysis/malloc.cpp
+++ b/test/Analysis/malloc.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -w -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus.NewDelete -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -w -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus.NewDelete -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus.NewDelete -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple i386-unknown-linux-gnu -w -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus.NewDelete -analyzer-store=region -verify %s
#include "Inputs/system-header-simulator-cxx.h"
diff --git a/test/Analysis/malloc.m b/test/Analysis/malloc.m
index 9201c2b75fe6..1f67daba55ec 100644
--- a/test/Analysis/malloc.m
+++ b/test/Analysis/malloc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -Wno-objc-root-class -fblocks %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -Wno-objc-root-class -fblocks %s
#include "Inputs/system-header-simulator-objc.h"
@class NSString;
@@ -29,7 +29,7 @@ void rdar10579586(char x);
if (error != ((void*)0))
return error;
- rdar10579586(buffer->str_c); // expected-warning {{Function call argument is an uninitialized value}}
+ rdar10579586(buffer->str_c); // expected-warning {{1st function call argument is an uninitialized value}}
free(buffer);
return ((void*)0);
}
diff --git a/test/Analysis/malloc.mm b/test/Analysis/malloc.mm
index c7fe86bf0bcc..f8a43b3b6a99 100644
--- a/test/Analysis/malloc.mm
+++ b/test/Analysis/malloc.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
#import "Inputs/system-header-simulator-objc.h"
#import "Inputs/system-header-simulator-for-malloc.h"
diff --git a/test/Analysis/max-nodes-suppress-on-sink.c b/test/Analysis/max-nodes-suppress-on-sink.c
index c45bee8203df..8d955b91c1e3 100644
--- a/test/Analysis/max-nodes-suppress-on-sink.c
+++ b/test/Analysis/max-nodes-suppress-on-sink.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config max-nodes=12 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config max-nodes=12 -verify %s
// Here we test how "suppress on sink" feature of certain bugtypes interacts
// with reaching analysis limits.
diff --git a/test/Analysis/member-expr.cpp b/test/Analysis/member-expr.cpp
index f8dd324e9857..9951943e3060 100644
--- a/test/Analysis/member-expr.cpp
+++ b/test/Analysis/member-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection %s -verify
void clang_analyzer_checkInlined(bool);
void clang_analyzer_eval(int);
diff --git a/test/Analysis/method-call-intra-p.cpp b/test/Analysis/method-call-intra-p.cpp
index a1709428402c..bead20fecd54 100644
--- a/test/Analysis/method-call-intra-p.cpp
+++ b/test/Analysis/method-call-intra-p.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store region -verify %s
// expected-no-diagnostics
// Intra-procedural C++ tests.
diff --git a/test/Analysis/method-call-path-notes.cpp b/test/Analysis/method-call-path-notes.cpp
index 8eb07d550a61..e6253d4f89c3 100644
--- a/test/Analysis/method-call-path-notes.cpp
+++ b/test/Analysis/method-call-path-notes.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
// Test warning about null or uninitialized pointer values used as instance member
diff --git a/test/Analysis/method-call.cpp b/test/Analysis/method-call.cpp
index 95db452aec6a..4f6a9a430a78 100644
--- a/test/Analysis/method-call.cpp
+++ b/test/Analysis/method-call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m
index be50d4606d4f..50c0e9795d86 100644
--- a/test/Analysis/misc-ps-64.m
+++ b/test/Analysis/misc-ps-64.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
// expected-no-diagnostics
// <rdar://problem/6440393> - A bunch of misc. failures involving evaluating
diff --git a/test/Analysis/misc-ps-arm.m b/test/Analysis/misc-ps-arm.m
index a9ea3274ae4b..9cb7bb202fef 100644
--- a/test/Analysis/misc-ps-arm.m
+++ b/test/Analysis/misc-ps-arm.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple thumbv7-apple-ios0.0.0 -target-feature +neon -analyze -analyzer-checker=core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple thumbv7-apple-ios0.0.0 -target-feature +neon -analyzer-checker=core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
// expected-no-diagnostics
// <rdar://problem/11405978> - Handle casts of vectors to structs, and loading
diff --git a/test/Analysis/misc-ps-cxx0x.cpp b/test/Analysis/misc-ps-cxx0x.cpp
index 164af5dc3dfe..1b4516af7880 100644
--- a/test/Analysis/misc-ps-cxx0x.cpp
+++ b/test/Analysis/misc-ps-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze -std=c++11 %s -Xclang -verify -o /dev/null
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.NullDereference,core.uninitialized.UndefReturn -std=c++11 %s -verify -o /dev/null
void test_static_assert() {
static_assert(sizeof(void *) == sizeof(void*), "test_static_assert");
diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m
index ca056d8fff9e..dbeecf235f9f 100644
--- a/test/Analysis/misc-ps-eager-assume.m
+++ b/test/Analysis/misc-ps-eager-assume.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s -analyzer-eagerly-assume
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s -analyzer-eagerly-assume
// expected-no-diagnostics
// Delta-reduced header stuff (needed for test cases).
diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m
index d8720e9a377c..161d9817bcf1 100644
--- a/test/Analysis/misc-ps-ranges.m
+++ b/test/Analysis/misc-ps-ranges.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
// <rdar://problem/6776949>
// main's 'argc' argument is always > 0
diff --git a/test/Analysis/misc-ps-region-store-i386.m b/test/Analysis/misc-ps-region-store-i386.m
index bed6fc30d315..269a8155b12a 100644
--- a/test/Analysis/misc-ps-region-store-i386.m
+++ b/test/Analysis/misc-ps-region-store-i386.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
// expected-no-diagnostics
// Here is a case where a pointer is treated as integer, invalidated as an
diff --git a/test/Analysis/misc-ps-region-store-x86_64.m b/test/Analysis/misc-ps-region-store-x86_64.m
index 4575ad44977b..0bdc5a2b6a26 100644
--- a/test/Analysis/misc-ps-region-store-x86_64.m
+++ b/test/Analysis/misc-ps-region-store-x86_64.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
// expected-no-diagnostics
// Here is a case where a pointer is treated as integer, invalidated as an
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index daa6d64f2bd5..c6dad5dd9d6e 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions -Wno-tautological-undefined-compare
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions -Wno-tautological-undefined-compare
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions -Wno-tautological-undefined-compare
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions -Wno-tautological-undefined-compare
void clang_analyzer_warnIfReached();
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 58166484b822..9bd207326350 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core.CastToStruct,alpha.security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,alpha.core.CastToStruct,alpha.security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core.CastToStruct,alpha.security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyzer-checker=core,alpha.core.CastToStruct,alpha.security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
typedef long unsigned int size_t;
void *memcpy(void *, const void *, size_t);
@@ -396,7 +396,7 @@ void rdar_7332673_test1() {
int rdar_7332673_test2_aux(char *x);
void rdar_7332673_test2() {
char *value;
- if ( rdar_7332673_test2_aux(value) != 1 ) {} // expected-warning{{Function call argument is an uninitialized value}}
+ if ( rdar_7332673_test2_aux(value) != 1 ) {} // expected-warning{{1st function call argument is an uninitialized value}}
}
//===----------------------------------------------------------------------===//
@@ -673,7 +673,7 @@ typedef void (^RDar_7462324_Callback)(id obj);
builder = ^(id object) {
id x;
if (object) {
- builder(x); // expected-warning{{Block call argument is an uninitialized value}}
+ builder(x); // expected-warning{{1st block call argument is an uninitialized value}}
}
};
builder(target);
diff --git a/test/Analysis/misc-ps-region-store.mm b/test/Analysis/misc-ps-region-store.mm
index c19a90f011c8..4b271c4512dc 100644
--- a/test/Analysis/misc-ps-region-store.mm
+++ b/test/Analysis/misc-ps-region-store.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
// expected-no-diagnostics
//===------------------------------------------------------------------------------------------===//
diff --git a/test/Analysis/misc-ps.c b/test/Analysis/misc-ps.c
index ad65437e4c1d..3044dc98d3c7 100644
--- a/test/Analysis/misc-ps.c
+++ b/test/Analysis/misc-ps.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index f979cf3eed82..9a75cfd87b62 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1,6 +1,6 @@
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-store=region -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-store=region -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-store=region -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-store=region -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
#ifndef __clang_analyzer__
#error __clang_analyzer__ not defined
@@ -796,7 +796,7 @@ int test_uninit_branch_c(void) {
void test_bad_call_aux(int x);
void test_bad_call(void) {
int y;
- test_bad_call_aux(y); // expected-warning{{Function call argument is an uninitialized value}}
+ test_bad_call_aux(y); // expected-warning{{1st function call argument is an uninitialized value}}
}
@interface TestBadArg {}
@@ -805,7 +805,7 @@ void test_bad_call(void) {
void test_bad_msg(TestBadArg *p) {
int y;
- [p testBadArg:y]; // expected-warning{{Argument in message expression is an uninitialized value}}
+ [p testBadArg:y]; // expected-warning{{1st argument in message expression is an uninitialized value}}
}
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/model-file.cpp b/test/Analysis/model-file.cpp
index 41cdf7fef48c..de5a888ab223 100644
--- a/test/Analysis/model-file.cpp
+++ b/test/Analysis/model-file.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config faux-bodies=true,model-path=%S/Inputs/Models -analyzer-output=plist-multi-file -verify %s -o %t
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config faux-bodies=true,model-path=%S/Inputs/Models -analyzer-output=plist-multi-file -verify %s -o %t
// RUN: FileCheck --input-file=%t %s
typedef int* intptr;
diff --git a/test/Analysis/mpichecker.cpp b/test/Analysis/mpichecker.cpp
index b7a1e00e00b4..f7644520ebcf 100644
--- a/test/Analysis/mpichecker.cpp
+++ b/test/Analysis/mpichecker.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=optin.mpi.MPI-Checker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.mpi.MPI-Checker -verify %s
#include "MPIMock.h"
diff --git a/test/Analysis/mpicheckernotes.cpp b/test/Analysis/mpicheckernotes.cpp
index be312fdf5fda..994ce8e302dd 100644
--- a/test/Analysis/mpicheckernotes.cpp
+++ b/test/Analysis/mpicheckernotes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=optin.mpi.MPI-Checker -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.mpi.MPI-Checker -analyzer-output=text -verify %s
// MPI-Checker test file to test note diagnostics.
diff --git a/test/Analysis/new-with-exceptions.cpp b/test/Analysis/new-with-exceptions.cpp
index 84d77c22302c..9d02574229c1 100644
--- a/test/Analysis/new-with-exceptions.cpp
+++ b/test/Analysis/new-with-exceptions.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -fexceptions -fcxx-exceptions -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -fexceptions -fcxx-exceptions -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/new.cpp b/test/Analysis/new.cpp
index e262aa727e2b..6cfcb1d92719 100644
--- a/test/Analysis/new.cpp
+++ b/test/Analysis/new.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
#include "Inputs/system-header-simulator-cxx.h"
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
index e63e2cafaf42..cbfc266b7bee 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin8 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
// <rdar://problem/6888289> - This test case shows that a nil instance
// variable can possibly be initialized by a method.
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
index 4f9939040446..d4a478d327e3 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s > %t.1 2>&1
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin8 -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s > %t.1 2>&1
// RUN: FileCheck -input-file=%t.1 -check-prefix=CHECK-darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s > %t.2 2>&1
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s > %t.2 2>&1
// RUN: FileCheck -input-file=%t.2 -check-prefix=CHECK-darwin9 %s
-// RUN: %clang_cc1 -triple thumbv6-apple-ios4.0 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s > %t.3 2>&1
+// RUN: %clang_analyze_cc1 -triple thumbv6-apple-ios4.0 -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s > %t.3 2>&1
// RUN: FileCheck -input-file=%t.3 -check-prefix=CHECK-darwin9 %s
@interface MyClass {}
diff --git a/test/Analysis/no-exit-cfg.c b/test/Analysis/no-exit-cfg.c
index b3c3fbcc6241..7575152295eb 100644
--- a/test/Analysis/no-exit-cfg.c
+++ b/test/Analysis/no-exit-cfg.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
// This is a test case for the issue reported in PR 2819:
diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c
index d4012794d5c7..ae534a94a241 100644
--- a/test/Analysis/no-outofbounds.c
+++ b/test/Analysis/no-outofbounds.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,alpha.unix,alpha.security.ArrayBound -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,alpha.unix,alpha.security.ArrayBound -analyzer-store=region -verify %s
// expected-no-diagnostics
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/no-unreachable-dtors.cpp b/test/Analysis/no-unreachable-dtors.cpp
index e0893b3f4e62..1675542d9ac7 100644
--- a/test/Analysis/no-unreachable-dtors.cpp
+++ b/test/Analysis/no-unreachable-dtors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.Stats -verify -Wno-unreachable-code %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.Stats -verify -Wno-unreachable-code %s
struct S {
~S();
diff --git a/test/Analysis/non-diagnosable-assumptions.c b/test/Analysis/non-diagnosable-assumptions.c
index 50cc8d603b95..44b69bed7c27 100644
--- a/test/Analysis/non-diagnosable-assumptions.c
+++ b/test/Analysis/non-diagnosable-assumptions.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -w -analyze -analyzer-checker=core.DivideZero -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core.DivideZero -analyzer-output=text -verify %s
// This test file verifies the "Assuming..." diagnostic pieces that are being
// reported when the branch condition was too complicated to explain.
diff --git a/test/Analysis/nonnull.m b/test/Analysis/nonnull.m
index c21360ded8d1..6db7cfaf4917 100644
--- a/test/Analysis/nonnull.m
+++ b/test/Analysis/nonnull.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -w -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -w -verify %s
@interface MyObject
- (void)takePointer:(void *)ptr __attribute__((nonnull(1)));
diff --git a/test/Analysis/null-deref-path-notes.m b/test/Analysis/null-deref-path-notes.m
index 9e5cab6e7430..242b5daa9bfc 100644
--- a/test/Analysis/null-deref-path-notes.m
+++ b/test/Analysis/null-deref-path-notes.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-output=text -fblocks -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false -fblocks -Wno-objc-root-class %s -o %t
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -analyzer-output=text -fblocks -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false -fblocks -Wno-objc-root-class %s -o %t
// RUN: FileCheck --input-file=%t %s
@interface Root {
diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
index 5bb945486fbc..6ef99ae473ca 100644
--- a/test/Analysis/null-deref-ps-region.c
+++ b/test/Analysis/null-deref-ps-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index b0d2292547f6..5dee308a003d 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -analyzer-purge=none -verify %s -Wno-error=return-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -verify %s -Wno-error=return-type
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -analyzer-purge=none -verify %s -Wno-error=return-type
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -verify %s -Wno-error=return-type
typedef unsigned uintptr_t;
@@ -286,7 +286,7 @@ void pr4759_aux(int *p) __attribute__((nonnull));
void pr4759() {
int *p;
- pr4759_aux(p); // expected-warning{{Function call argument is an uninitialized value}}
+ pr4759_aux(p); // expected-warning{{1st function call argument is an uninitialized value}}
}
// Relax function call arguments invalidation to be aware of const
diff --git a/test/Analysis/nullability-no-arc.mm b/test/Analysis/nullability-no-arc.mm
index e872266d2770..0760186f4243 100644
--- a/test/Analysis/nullability-no-arc.mm
+++ b/test/Analysis/nullability-no-arc.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,nullability -verify %s
#define nil 0
diff --git a/test/Analysis/nullability.c b/test/Analysis/nullability.c
index a282969e03d4..e0836c6798bb 100644
--- a/test/Analysis/nullability.c
+++ b/test/Analysis/nullability.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability -verify %s
void it_takes_two(int a, int b);
void function_pointer_arity_mismatch() {
diff --git a/test/Analysis/nullability.mm b/test/Analysis/nullability.mm
index e4f13c6162cb..ddfede53b59d 100644
--- a/test/Analysis/nullability.mm
+++ b/test/Analysis/nullability.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -DNOSYSTEMHEADERS=0 -verify %s
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -DNOSYSTEMHEADERS=1 -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -DNOSYSTEMHEADERS=0 -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -DNOSYSTEMHEADERS=1 -verify %s
#include "Inputs/system-header-simulator-for-nullability.h"
diff --git a/test/Analysis/nullability_nullonly.mm b/test/Analysis/nullability_nullonly.mm
index 359841d97a62..18225391ee87 100644
--- a/test/Analysis/nullability_nullonly.mm
+++ b/test/Analysis/nullability_nullonly.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -DNOSYSTEMHEADERS=0 -verify %s
-// RUN: %clang_cc1 -analyze -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -DNOSYSTEMHEADERS=1 -verify %s
+// RUN: %clang_analyze_cc1 -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -DNOSYSTEMHEADERS=0 -verify %s
+// RUN: %clang_analyze_cc1 -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -DNOSYSTEMHEADERS=1 -verify %s
#include "Inputs/system-header-simulator-for-nullability.h"
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index acc525e9fef7..229ad7bbb555 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -Wno-conversion-null -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -Wno-conversion-null -analyzer-checker=core,debug.ExprInspection -analyzer-store region -verify %s
void clang_analyzer_eval(int);
@@ -107,7 +107,7 @@ struct Type {
void shouldNotCrash() {
decltype(nullptr) p;
if (getSymbol())
- invokeF(p); // expected-warning{{Function call argument is an uninit}}
+ invokeF(p); // expected-warning{{1st function call argument is an uninit}}
if (getSymbol())
invokeF(nullptr);
if (getSymbol()) {
diff --git a/test/Analysis/number-object-conversion.c b/test/Analysis/number-object-conversion.c
index c4ffaaffef12..8f1e67217974 100644
--- a/test/Analysis/number-object-conversion.c
+++ b/test/Analysis/number-object-conversion.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -w -analyze -analyzer-checker=osx.NumberObjectConversion %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -w -analyze -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -w -analyzer-checker=osx.NumberObjectConversion %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -w -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
#define NULL ((void *)0)
diff --git a/test/Analysis/number-object-conversion.cpp b/test/Analysis/number-object-conversion.cpp
index 9dea7b067d08..7e46a2bee85a 100644
--- a/test/Analysis/number-object-conversion.cpp
+++ b/test/Analysis/number-object-conversion.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -w -std=c++11 -analyze -analyzer-checker=osx.NumberObjectConversion %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -w -std=c++11 -analyze -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -w -std=c++11 -analyzer-checker=osx.NumberObjectConversion %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -w -std=c++11 -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
#define NULL ((void *)0)
#include "Inputs/system-header-simulator-cxx.h" // for nullptr
diff --git a/test/Analysis/number-object-conversion.m b/test/Analysis/number-object-conversion.m
index 08d4a195431d..8bc03320e6d6 100644
--- a/test/Analysis/number-object-conversion.m
+++ b/test/Analysis/number-object-conversion.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -w -analyze -analyzer-checker=osx.NumberObjectConversion %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -w -analyze -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -fobjc-arc -w -analyze -analyzer-checker=osx.NumberObjectConversion %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -fobjc-arc -w -analyze -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -fblocks -w -analyzer-checker=osx.NumberObjectConversion %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -fblocks -w -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -fblocks -fobjc-arc -w -analyzer-checker=osx.NumberObjectConversion %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -fblocks -fobjc-arc -w -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
#include "Inputs/system-header-simulator-objc.h"
diff --git a/test/Analysis/objc-arc.m b/test/Analysis/objc-arc.m
index 2d47c18ba46e..4b446abc906f 100644
--- a/test/Analysis/objc-arc.m
+++ b/test/Analysis/objc-arc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-arc -analyzer-config path-diagnostics-alternate=true -analyzer-output=plist-multi-file -o %t.plist %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-arc -analyzer-config path-diagnostics-alternate=true -analyzer-output=plist-multi-file -o %t.plist %s
// RUN: FileCheck --input-file=%t.plist %s
typedef signed char BOOL;
diff --git a/test/Analysis/objc-bool.m b/test/Analysis/objc-bool.m
index a2d10cc3bade..98d0cb2773f6 100644
--- a/test/Analysis/objc-bool.m
+++ b/test/Analysis/objc-bool.m
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze %s -o %t -Xclang -verify
+// RUN: %clang_analyze_cc1 %s -o %t -verify
// expected-no-diagnostics
// Test handling of ObjC bool literals.
diff --git a/test/Analysis/objc-boxing.m b/test/Analysis/objc-boxing.m
index 73386f463bc8..963374b3ef3c 100644
--- a/test/Analysis/objc-boxing.m
+++ b/test/Analysis/objc-boxing.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-objc-literal-conversion -analyze -analyzer-checker=core,unix.Malloc,osx.cocoa.NonNilReturnValue,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -Wno-objc-literal-conversion -analyzer-checker=core,unix.Malloc,osx.cocoa.NonNilReturnValue,debug.ExprInspection -analyzer-store=region -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/objc-for.m b/test/Analysis/objc-for.m
index d1e044a6513b..41709bee359e 100644
--- a/test/Analysis/objc-for.m
+++ b/test/Analysis/objc-for.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/objc-message.m b/test/Analysis/objc-message.m
index dc0fd1f4c5c9..f525ce7968dd 100644
--- a/test/Analysis/objc-message.m
+++ b/test/Analysis/objc-message.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
extern void clang_analyzer_warnIfReached();
void clang_analyzer_eval(int);
diff --git a/test/Analysis/objc-method-coverage.m b/test/Analysis/objc-method-coverage.m
index 489c19ba6c62..1915586de93a 100644
--- a/test/Analysis/objc-method-coverage.m
+++ b/test/Analysis/objc-method-coverage.m
@@ -1,5 +1,5 @@
// REQUIRES: asserts
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-stats -fblocks %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-stats -fblocks %s 2>&1 | FileCheck %s
@interface I
int f() {
return 0;
diff --git a/test/Analysis/objc-properties.m b/test/Analysis/objc-properties.m
index f6ed3e5ef043..88a19a13c514 100644
--- a/test/Analysis/objc-properties.m
+++ b/test/Analysis/objc-properties.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignment -verify -fblocks %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignment -verify -fblocks %s
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
diff --git a/test/Analysis/objc-radar17039661.m b/test/Analysis/objc-radar17039661.m
index fc55ab1daeb4..bfb8ef02306b 100644
--- a/test/Analysis/objc-radar17039661.m
+++ b/test/Analysis/objc-radar17039661.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -fblocks -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -fblocks -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t
// RUN: FileCheck --input-file=%t %s
@class NSString;
typedef long NSInteger;
diff --git a/test/Analysis/objc-string.mm b/test/Analysis/objc-string.mm
index a32b740bba02..53f3c3736261 100644
--- a/test/Analysis/objc-string.mm
+++ b/test/Analysis/objc-string.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -Wno-objc-literal-conversion %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -Wno-objc-literal-conversion %s
void clang_analyzer_eval(bool);
@class NSString;
diff --git a/test/Analysis/objc-subscript.m b/test/Analysis/objc-subscript.m
index ae621c982873..155fbb7b6268 100644
--- a/test/Analysis/objc-subscript.m
+++ b/test/Analysis/objc-subscript.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify -Wno-objc-root-class %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m b/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
index 4777aed99d91..1603a57fea40 100644
--- a/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
+++ b/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions -verify -fblocks %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions -verify -fblocks %s
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
diff --git a/test/Analysis/objc_invalidation.m b/test/Analysis/objc_invalidation.m
index cd66444f4010..52a79d8f34ba 100644
--- a/test/Analysis/objc_invalidation.m
+++ b/test/Analysis/objc_invalidation.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -verify %s
extern void __assert_fail (__const char *__assertion, __const char *__file,
unsigned int __line, __const char *__function)
__attribute__ ((__noreturn__));
diff --git a/test/Analysis/openmp-unsupported.c b/test/Analysis/openmp-unsupported.c
new file mode 100644
index 000000000000..7e363eecbaa0
--- /dev/null
+++ b/test/Analysis/openmp-unsupported.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin -fopenmp -verify %s
+// expected-no-diagnostics
+
+void openmp_parallel_crash_test() {
+#pragma omp parallel
+ ;
+}
diff --git a/test/Analysis/operator-calls.cpp b/test/Analysis/operator-calls.cpp
index 4bd7c12fad32..310722965965 100644
--- a/test/Analysis/operator-calls.cpp
+++ b/test/Analysis/operator-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
struct X0 { };
diff --git a/test/Analysis/out-of-bounds-new.cpp b/test/Analysis/out-of-bounds-new.cpp
index ee7bb1ec444b..b7ceea72a270 100644
--- a/test/Analysis/out-of-bounds-new.cpp
+++ b/test/Analysis/out-of-bounds-new.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -Wno-array-bounds -analyze -analyzer-checker=unix,core,alpha.security.ArrayBoundV2 -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -Wno-array-bounds -analyzer-checker=unix,core,alpha.security.ArrayBoundV2 -verify %s
// Tests doing an out-of-bounds access after the end of an array using:
// - constant integer index
diff --git a/test/Analysis/out-of-bounds.c b/test/Analysis/out-of-bounds.c
index ca1e0d05006a..1970cd658c42 100644
--- a/test/Analysis/out-of-bounds.c
+++ b/test/Analysis/out-of-bounds.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,alpha.security.ArrayBoundV2,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,alpha.security.ArrayBoundV2,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/outofbound-notwork.c b/test/Analysis/outofbound-notwork.c
index 68b01e0f79c6..22ccd9e2c913 100644
--- a/test/Analysis/outofbound-notwork.c
+++ b/test/Analysis/outofbound-notwork.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,alpha.security.ArrayBound -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,alpha.security.ArrayBound -analyzer-store=region -verify %s
// XFAIL: *
// Once we better handle modeling of sizes of VLAs, we can pull this back
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
index 81ed7ac00b39..35672c0c448b 100644
--- a/test/Analysis/outofbound.c
+++ b/test/Analysis/outofbound.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,unix,alpha.security.ArrayBound -analyzer-store=region -verify -analyzer-config unix:Optimistic=true %s
+// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,unix,alpha.security.ArrayBound -analyzer-store=region -verify -analyzer-config unix:Optimistic=true %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
diff --git a/test/Analysis/override-werror.c b/test/Analysis/override-werror.c
index a68ee1ed0a30..7dc09f518627 100644
--- a/test/Analysis/override-werror.c
+++ b/test/Analysis/override-werror.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -Werror %s -analyzer-store=region -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -Werror %s -analyzer-store=region -verify
// This test case illustrates that using '-analyze' overrides the effect of
// -Werror. This allows basic warnings not to interfere with producing
diff --git a/test/Analysis/padding_c.c b/test/Analysis/padding_c.c
index 93cefcad8930..f4178f545791 100644
--- a/test/Analysis/padding_c.c
+++ b/test/Analysis/padding_c.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
#if __has_include(<stdalign.h>)
#include <stdalign.h>
diff --git a/test/Analysis/padding_cpp.cpp b/test/Analysis/padding_cpp.cpp
index df2f2a82d35c..ee49aea0c2be 100644
--- a/test/Analysis/padding_cpp.cpp
+++ b/test/Analysis/padding_cpp.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++14 -analyze -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
+// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
// Make sure that the C cases still work fine, even when compiled as C++.
#include "padding_c.c"
diff --git a/test/Analysis/padding_message.cpp b/test/Analysis/padding_message.cpp
index bbfa45394d85..4c7e06108154 100644
--- a/test/Analysis/padding_message.cpp
+++ b/test/Analysis/padding_message.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++14 -analyze -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -std=c++14 -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
// expected-warning@+7{{\
Excessive padding in 'struct IntSandwich' (6 padding bytes, where 2 is optimal). \
diff --git a/test/Analysis/plist-html-macros.c b/test/Analysis/plist-html-macros.c
index dbdbb30c4b2f..c25346d99a6d 100644
--- a/test/Analysis/plist-html-macros.c
+++ b/test/Analysis/plist-html-macros.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
// (sanity check)
// RUN: rm -rf %t.dir
// RUN: mkdir -p %t.dir
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-html -o %t.dir/index.plist %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-html -o %t.dir/index.plist %s
// RUN: ls %t.dir | grep '\.html' | count 1
// RUN: grep '\.html' %t.dir/index.plist | count 1
diff --git a/test/Analysis/plist-macros.cpp b/test/Analysis/plist-macros.cpp
index 09ad15e5a570..594cfdc6efc5 100644
--- a/test/Analysis/plist-macros.cpp
+++ b/test/Analysis/plist-macros.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -analyzer-eagerly-assume -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -analyzer-eagerly-assume -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=ture %s -o %t.plist
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -analyzer-eagerly-assume -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -analyzer-eagerly-assume -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=ture %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m
index 7c8e51385777..03f3393af8a7 100644
--- a/test/Analysis/plist-output-alternate.m
+++ b/test/Analysis/plist-output-alternate.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -fblocks -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -fblocks -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t %s
// RUN: FileCheck --input-file %t %s
void test_null_init(void) {
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index affbb5d14d9c..a80ab5c31c66 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze %s -Xanalyzer -analyzer-checker=osx.cocoa.RetainCount -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -Xanalyzer -analyzer-config -Xanalyzer path-diagnostics-alternate=false -o %t.plist
+// RUN: %clang_analyze_cc1 %s -analyzer-checker=osx.cocoa.RetainCount,deadcode.DeadStores,core -analyzer-output=plist -analyzer-config path-diagnostics-alternate=false -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
void test_null_init(void) {
@@ -24,7 +24,7 @@ void test_null_cond(int *p) {
*p = 0xDEADBEEF;
}
}
-
+
void test_null_cond_transitive(int *q) {
if (!q) {
int *p = q;
@@ -51,7 +51,7 @@ void test_assumptions(int a, int b)
}
int *bar_cond_assign();
-int test_cond_assign() {
+int test_cond_assign() {
int *p;
if (p = bar_cond_assign())
return 1;
@@ -138,7 +138,7 @@ void test_loop_diagnostics() {
void test_loop_diagnostics_2() {
int *p = 0;
- for (int i = 0; i < 2; ) {
+ for (int i = 0; i < 2; ) {
++i;
p = 0;
}
@@ -166,9 +166,9 @@ void test_loop_fast_enumeration(id arr) {
@interface RDar12114812 { char *p; }
@end
-@implementation RDar12114812
+@implementation RDar12114812
- (void)test {
- p = 0;
+ p = 0;
*p = 1;
}
@end
@@ -2686,103 +2686,6 @@ int testFoo(Foo *x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>108</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
@@ -2992,103 +2895,6 @@ int testFoo(Foo *x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>117</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
diff --git a/test/Analysis/pointer-to-member.cpp b/test/Analysis/pointer-to-member.cpp
index 039782b44b74..0fbb992dd82a 100644
--- a/test/Analysis/pointer-to-member.cpp
+++ b/test/Analysis/pointer-to-member.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/pr22954.c b/test/Analysis/pr22954.c
index 01aa5b34a7eb..64a00c5ec087 100644
--- a/test/Analysis/pr22954.c
+++ b/test/Analysis/pr22954.c
@@ -3,7 +3,7 @@
// At the moment the whole of the destination array content is invalidated.
// If a.s1 region has a symbolic offset, the whole region of 'a' is invalidated.
// Specific triple set to test structures of size 0.
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index 29abe94441da..8b0eacad9694 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-incomplete-implementation -verify %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-incomplete-implementation -verify %s
// This test case was crashing due to how CFRefCount.cpp resolved the
// ObjCInterfaceDecl* and ClassName in EvalObjCMessageExpr.
diff --git a/test/Analysis/pr_2542_rdar_6793404.m b/test/Analysis/pr_2542_rdar_6793404.m
index 6f1ebf962594..5df40e88fcb4 100644
--- a/test/Analysis/pr_2542_rdar_6793404.m
+++ b/test/Analysis/pr_2542_rdar_6793404.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -pedantic -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -pedantic -analyzer-store=region -verify -Wno-objc-root-class %s
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/pr_4164.c b/test/Analysis/pr_4164.c
index 0d2ca41b32e1..02c1f41ebbd5 100644
--- a/test/Analysis/pr_4164.c
+++ b/test/Analysis/pr_4164.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
// PR 4164: http://llvm.org/bugs/show_bug.cgi?id=4164
diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m
index 235a9687821d..e792bb2e6bad 100644
--- a/test/Analysis/properties.m
+++ b/test/Analysis/properties.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
void clang_analyzer_eval(int);
@@ -987,5 +987,21 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) {
}
@end
+
+@interface Wrapper
+@property(nonatomic, readonly) int value;
+@end
+
+@implementation Wrapper
+@synthesize value;
+@end
+
+void testNoCrashWhenAccessPropertyAndThereAreNoDirectBindingsAtAll() {
+ union {
+ Wrapper *wrapper;
+ } u = { 0 };
+ [u.wrapper value];
+}
+
#endif // non-ARC
diff --git a/test/Analysis/properties.mm b/test/Analysis/properties.mm
index e49d034f2651..2d93d6dc6385 100644
--- a/test/Analysis/properties.mm
+++ b/test/Analysis/properties.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
diff --git a/test/Analysis/pthreadlock.c b/test/Analysis/pthreadlock.c
index a6e29e78ff38..98868172523d 100644
--- a/test/Analysis/pthreadlock.c
+++ b/test/Analysis/pthreadlock.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.unix.PthreadLock -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.unix.PthreadLock -verify %s
// Tests performing normal locking patterns and wrong locking orders
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index 2b15badf4274..b78ec503a1ca 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple x86_64-apple-darwin9 -Wno-tautological-pointer-compare %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple i686-apple-darwin9 -Wno-tautological-pointer-compare %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple x86_64-apple-darwin9 -Wno-tautological-pointer-compare %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple i686-apple-darwin9 -Wno-tautological-pointer-compare %s
void clang_analyzer_eval(int);
@@ -213,7 +213,12 @@ void comparisons_imply_size(int *lhs, int *rhs) {
}
clang_analyzer_eval(lhs <= rhs); // expected-warning{{TRUE}}
+// FIXME: In Z3ConstraintManager, ptrdiff_t is mapped to signed bitvector. However, this does not directly imply the unsigned comparison.
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{UNKNOWN}}
+#else
clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{TRUE}}
+#endif
clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
if (lhs >= rhs) {
@@ -223,7 +228,11 @@ void comparisons_imply_size(int *lhs, int *rhs) {
clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
clang_analyzer_eval(lhs < rhs); // expected-warning{{TRUE}}
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
+#else
clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
+#endif
}
void size_implies_comparison(int *lhs, int *rhs) {
@@ -234,7 +243,11 @@ void size_implies_comparison(int *lhs, int *rhs) {
return;
}
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
+#else
clang_analyzer_eval(lhs <= rhs); // expected-warning{{TRUE}}
+#endif
clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{TRUE}}
clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
@@ -244,7 +257,11 @@ void size_implies_comparison(int *lhs, int *rhs) {
}
clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{UNKNOWN}}
+#else
clang_analyzer_eval(lhs < rhs); // expected-warning{{TRUE}}
+#endif
clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
}
@@ -255,30 +272,42 @@ void size_implies_comparison(int *lhs, int *rhs) {
void zero_implies_reversed_equal(int *lhs, int *rhs) {
clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}}
if ((rhs - lhs) == 0) {
- // FIXME: Should be FALSE.
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(rhs != lhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(rhs == lhs); // expected-warning{{TRUE}}
+#else
clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}}
- // FIXME: Should be TRUE.
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
+#endif
return;
}
clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
- // FIXME: Should be FALSE.
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(rhs == lhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(rhs != lhs); // expected-warning{{TRUE}}
+#else
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
- // FIXME: Should be TRUE.
clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}}
+#endif
}
void canonical_equal(int *lhs, int *rhs) {
clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}}
if (lhs == rhs) {
- // FIXME: Should be TRUE.
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(rhs == lhs); // expected-warning{{TRUE}}
+#else
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
+#endif
return;
}
clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
- // FIXME: Should be FALSE.
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(rhs == lhs); // expected-warning{{FALSE}}
+#else
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
+#endif
}
void compare_element_region_and_base(int *p) {
diff --git a/test/Analysis/ptr-arith.cpp b/test/Analysis/ptr-arith.cpp
index 07ddec30af56..e1860f4268e0 100644
--- a/test/Analysis/ptr-arith.cpp
+++ b/test/Analysis/ptr-arith.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-unused-value -std=c++14 -analyze -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm -verify %s
+// RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm -verify %s
struct X {
int *p;
int zero;
diff --git a/test/Analysis/qt_malloc.cpp b/test/Analysis/qt_malloc.cpp
index 200556ea306d..ad25634d87b0 100644
--- a/test/Analysis/qt_malloc.cpp
+++ b/test/Analysis/qt_malloc.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus -analyzer-store=region -verify %s
// expected-no-diagnostics
#include "Inputs/qt-simulator.h"
diff --git a/test/Analysis/range_casts.c b/test/Analysis/range_casts.c
index 682369cce66f..a01ab5d52097 100644
--- a/test/Analysis/range_casts.c
+++ b/test/Analysis/range_casts.c
@@ -1,5 +1,5 @@
// This test checks that intersecting ranges does not cause 'system is over constrained' assertions in the case of eg: 32 bits unsigned integers getting their range from 64 bits signed integers.
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify %s
void clang_analyzer_warnIfReached();
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
index 31a300c1f66f..d84000076d79 100644
--- a/test/Analysis/rdar-6442306-1.m
+++ b/test/Analysis/rdar-6442306-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-disable-checker=alpha.core.PointerArithm %s -analyzer-store=region -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-disable-checker=alpha.core.PointerArithm %s -analyzer-store=region -verify
// expected-no-diagnostics
typedef int bar_return_t;
diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m
index 2119df5b9ef5..da7d42c3722e 100644
--- a/test/Analysis/rdar-6540084.m
+++ b/test/Analysis/rdar-6540084.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-checker=deadcode.DeadStores -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-checker=deadcode.DeadStores -verify %s
//
// This test exercises the live variables analysis (LiveVariables.cpp).
// The case originally identified a non-termination bug.
diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c
index 83b7605b9511..dc75af43e491 100644
--- a/test/Analysis/rdar-6541136-region.c
+++ b/test/Analysis/rdar-6541136-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,alpha.security.ArrayBound -analyzer-store=region %s
+// RUN: %clang_analyze_cc1 -verify -analyzer-checker=core,alpha.security.ArrayBound -analyzer-store=region %s
struct tea_cheese { unsigned magic; };
typedef struct tea_cheese kernel_tea_cheese_t;
diff --git a/test/Analysis/rdar-6562655.m b/test/Analysis/rdar-6562655.m
index 9591f551f3d9..8794cacb74a0 100644
--- a/test/Analysis/rdar-6562655.m
+++ b/test/Analysis/rdar-6562655.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
//
// This test case mainly checks that the retain/release checker doesn't crash
diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
index e9809db50119..72dbe422b63a 100644
--- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
+++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -Wno-objc-root-class %s
// expected-no-diagnostics
typedef struct Foo { int x; } Bar;
diff --git a/test/Analysis/rdar-7168531.m b/test/Analysis/rdar-7168531.m
index b128d32bfdea..b2b1511dd2ab 100644
--- a/test/Analysis/rdar-7168531.m
+++ b/test/Analysis/rdar-7168531.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -analyzer-store=region %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -analyzer-store=region %s
// Note that the target triple is important for this test case. It specifies that we use the
// fragile Objective-C ABI.
diff --git a/test/Analysis/redefined_system.c b/test/Analysis/redefined_system.c
index 16f03abe12e5..4901b3ae616f 100644
--- a/test/Analysis/redefined_system.c
+++ b/test/Analysis/redefined_system.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx,unix,core,alpha.security.taint -w -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx,unix,core,alpha.security.taint -w -verify %s
// expected-no-diagnostics
// Make sure we don't crash when someone redefines a system function we reason about.
diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m
index cff5970b315a..c77909a0c277 100644
--- a/test/Analysis/refcnt_naming.m
+++ b/test/Analysis/refcnt_naming.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-config ipa=none -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-config ipa=none -analyzer-store=region -verify %s
typedef const struct __CFString * CFStringRef;
typedef const struct __CFAllocator * CFAllocatorRef;
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index 951079d43e47..b323b966610a 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -Wno-null-dereference -Wno-tautological-undefined-compare %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -Wno-null-dereference -Wno-tautological-undefined-compare %s
void clang_analyzer_eval(bool);
@@ -118,16 +118,30 @@ void testRetroactiveNullReference(int *x) {
}
void testReferenceAddress(int &x) {
+// FIXME: Move non-zero reference assumption out of RangeConstraintManager.cpp:422
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(&x != 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(&ref() != 0); // expected-warning{{UNKNOWN}}
+#else
clang_analyzer_eval(&x != 0); // expected-warning{{TRUE}}
clang_analyzer_eval(&ref() != 0); // expected-warning{{TRUE}}
+#endif
struct S { int &x; };
extern S getS();
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}}
+#else
clang_analyzer_eval(&getS().x != 0); // expected-warning{{TRUE}}
+#endif
extern S *getSP();
+#ifdef ANALYZER_CM_Z3
+ clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{UNKNOWN}}
+#else
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}
+#endif
}
diff --git a/test/Analysis/reference.mm b/test/Analysis/reference.mm
index c5546aac5fcd..1d73ccd6ead3 100644
--- a/test/Analysis/reference.mm
+++ b/test/Analysis/reference.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -Wno-null-dereference %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -Wno-null-dereference %s
@interface Foo
- (int &)ref;
diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m
index 6940c69dc1bc..3245bd4cf744 100644
--- a/test/Analysis/region-1.m
+++ b/test/Analysis/region-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
// expected-no-diagnostics
//
// This test case simply should not crash. It evaluates the logic of not
diff --git a/test/Analysis/region-store.c b/test/Analysis/region-store.c
index 70bda1117b0e..673baafa0959 100644
--- a/test/Analysis/region-store.c
+++ b/test/Analysis/region-store.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection -verify %s
int printf(const char *restrict,...);
diff --git a/test/Analysis/region-store.cpp b/test/Analysis/region-store.cpp
index 5ea5c3f82fd6..cb49f4837d81 100644
--- a/test/Analysis/region-store.cpp
+++ b/test/Analysis/region-store.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -verify %s
// expected-no-diagnostics
class Loc {
diff --git a/test/Analysis/reinterpret-cast.cpp b/test/Analysis/reinterpret-cast.cpp
index f3b0a7b257b6..7b8c2f3ee9a4 100644
--- a/test/Analysis/reinterpret-cast.cpp
+++ b/test/Analysis/reinterpret-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/retain-release-arc.m b/test/Analysis/retain-release-arc.m
index 6f3cbfbe5a9f..78115ac5bde0 100644
--- a/test/Analysis/retain-release-arc.m
+++ b/test/Analysis/retain-release-arc.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fobjc-arc -fblocks -verify -Wno-objc-root-class %s -analyzer-output=text
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s -analyzer-output=text
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fobjc-arc -fblocks -verify -Wno-objc-root-class %s -analyzer-output=text
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s -analyzer-output=text
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/retain-release-cache-out.m b/test/Analysis/retain-release-cache-out.m
index 54573a460638..5e9ebc4ad661 100644
--- a/test/Analysis/retain-release-cache-out.m
+++ b/test/Analysis/retain-release-cache-out.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze %s -analyzer-checker=core,osx.cocoa.RetainCount -fblocks -verify
+// RUN: %clang_analyze_cc1 %s -analyzer-checker=core,osx.cocoa.RetainCount -fblocks -verify
// This test is checking behavior when a single checker runs only with the core
// checkers, testing that the traversal order in the CFG does not affect the
diff --git a/test/Analysis/retain-release-cf-audited.m b/test/Analysis/retain-release-cf-audited.m
index c89172f70bef..414ccd53b309 100644
--- a/test/Analysis/retain-release-cf-audited.m
+++ b/test/Analysis/retain-release-cf-audited.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -verify %s -x objective-c++
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.cocoa.RetainCount -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.cocoa.RetainCount -verify %s -x objective-c++
// The special thing about this file is that CFRetain and CFRelease are marked
// as cf_audited_transfer.
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index 26eb6e12be20..6305942ac20a 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -triple %itanium_abi_triple -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify -Wno-objc-root-class %s
//===----------------------------------------------------------------------===//
// Header stuff.
diff --git a/test/Analysis/retain-release-inline.m b/test/Analysis/retain-release-inline.m
index 8809c8c84446..0cde2c1cf5af 100644
--- a/test/Analysis/retain-release-inline.m
+++ b/test/Analysis/retain-release-inline.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fblocks -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m
index 5b5558215060..04f991263c00 100644
--- a/test/Analysis/retain-release-path-notes-gc.m
+++ b/test/Analysis/retain-release-path-notes-gc.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fobjc-gc-only -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fobjc-gc-only -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fobjc-gc-only -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fobjc-gc-only -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
/***
diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
index 23347bc3aa73..f44d40fa495b 100644
--- a/test/Analysis/retain-release-path-notes.m
+++ b/test/Analysis/retain-release-path-notes.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=plist-multi-file -analyzer-config path-diagnostics-alternate=false %s -o %t
// RUN: FileCheck --input-file=%t %s
/***
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
index 3f83fb582834..65a31cc91ada 100644
--- a/test/Analysis/retain-release-region-store.m
+++ b/test/Analysis/retain-release-region-store.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-max-loop 6 -verify %s
+// RUN: %clang_analyze_cc1 -triple %itanium_abi_triple -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-max-loop 6 -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index b883a86602ba..39a3baa8960c 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1,6 +1,6 @@
// RUN: rm -f %t.objc.plist %t.objcpp.plist
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s -analyzer-output=plist -o %t.objc.plist
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ -std=gnu++98 -Wno-objc-root-class %s -analyzer-output=plist -o %t.objcpp.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s -analyzer-output=plist -o %t.objc.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ -std=gnu++98 -Wno-objc-root-class %s -analyzer-output=plist -o %t.objcpp.plist
// FIXLATER: cat %t.objc.plist ; FileCheck --input-file=%t.objc.plist %s
// FIXLATER: cat %t.objcpp.plist ; FileCheck --input-file=%t.objcpp.plist %s
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index 3650d887244b..c9817005c2c5 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify %s
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
diff --git a/test/Analysis/return-ptr-range.cpp b/test/Analysis/return-ptr-range.cpp
index 0cc17b05042b..dd5dcd5d5d19 100644
--- a/test/Analysis/return-ptr-range.cpp
+++ b/test/Analysis/return-ptr-range.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.ReturnPtrRange -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.ReturnPtrRange -verify %s
int arr[10];
int *ptr;
diff --git a/test/Analysis/security-syntax-checks-no-emit.c b/test/Analysis/security-syntax-checks-no-emit.c
index 7759aa73b33b..29dd2017745e 100644
--- a/test/Analysis/security-syntax-checks-no-emit.c
+++ b/test/Analysis/security-syntax-checks-no-emit.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple i686-pc-linux-gnu -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
// expected-no-diagnostics
// This file complements 'security-syntax-checks.m', but tests that we omit
diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m
index 9b7fb25edb19..04a4c7d86655 100644
--- a/test/Analysis/security-syntax-checks.m
+++ b/test/Analysis/security-syntax-checks.m
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
-// RUN: %clang_cc1 -triple x86_64-unknown-cloudabi -analyze -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
-// RUN: %clang_cc1 -triple x86_64-unknown-cloudabi -analyze -DUSE_BUILTINS -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
-// RUN: %clang_cc1 -triple x86_64-unknown-cloudabi -analyze -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
-// RUN: %clang_cc1 -triple x86_64-unknown-cloudabi -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DUSE_BUILTINS -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DUSE_BUILTINS -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-cloudabi -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-cloudabi -DUSE_BUILTINS -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-cloudabi -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-cloudabi -DUSE_BUILTINS -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
#ifdef USE_BUILTINS
# define BUILTIN(f) __builtin_ ## f
diff --git a/test/Analysis/self-assign.cpp b/test/Analysis/self-assign.cpp
index 74fb0fea2476..580a3ab00ead 100644
--- a/test/Analysis/self-assign.cpp
+++ b/test/Analysis/self-assign.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,cplusplus,unix.Malloc,debug.ExprInspection %s -verify -analyzer-output=text
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,unix.Malloc,debug.ExprInspection %s -verify -analyzer-output=text
extern "C" char *strdup(const char* s);
extern "C" void free(void* ptr);
diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m
index d1fb88de5410..cb1a321e8bbb 100644
--- a/test/Analysis/self-init.m
+++ b/test/Analysis/self-init.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -analyzer-config ipa=dynamic -fno-builtin %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fno-builtin %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.cocoa.SelfInit -analyzer-config ipa=dynamic -fno-builtin %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.cocoa.SelfInit -fno-builtin %s -verify
@class NSZone, NSCoder;
@protocol NSObject
diff --git a/test/Analysis/shallow-mode.m b/test/Analysis/shallow-mode.m
index 23df6990d49d..1c71e1b38fce 100644
--- a/test/Analysis/shallow-mode.m
+++ b/test/Analysis/shallow-mode.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config mode=shallow -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config mode=shallow -verify %s
// expected-no-diagnostics
void clang_analyzer_checkInlined(unsigned);
diff --git a/test/Analysis/simple-stream-checks.c b/test/Analysis/simple-stream-checks.c
index 2f725745a5ba..ca1c78157547 100644
--- a/test/Analysis/simple-stream-checks.c
+++ b/test/Analysis/simple-stream-checks.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.unix.SimpleStream -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.SimpleStream -verify %s
#include "Inputs/system-header-simulator-for-simple-stream.h"
@@ -65,7 +65,7 @@ void SymbolEscapedThroughFunctionCall() {
}
FILE *GlobalF;
-void SymbolEscapedThroughAssignmentToGloabl() {
+void SymbolEscapedThroughAssignmentToGlobal() {
FILE *F = fopen("myfile.txt", "w");
GlobalF = F;
return; // no warning
diff --git a/test/Analysis/sizeofpointer.c b/test/Analysis/sizeofpointer.c
index a9e045b4af53..14ddbd1a8b10 100644
--- a/test/Analysis/sizeofpointer.c
+++ b/test/Analysis/sizeofpointer.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.SizeofPtr -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.SizeofPtr -verify %s
struct s {
};
diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c
index d668f8fbee2d..4026cee90b04 100644
--- a/test/Analysis/stack-addr-ps.c
+++ b/test/Analysis/stack-addr-ps.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
int* f1() {
int x = 0;
diff --git a/test/Analysis/stack-addr-ps.cpp b/test/Analysis/stack-addr-ps.cpp
index a4ab2f3985c6..79afd18e1889 100644
--- a/test/Analysis/stack-addr-ps.cpp
+++ b/test/Analysis/stack-addr-ps.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s -Wno-undefined-bool-conversion
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -verify %s -Wno-undefined-bool-conversion
typedef __INTPTR_TYPE__ intptr_t;
diff --git a/test/Analysis/stack-block-returned.cpp b/test/Analysis/stack-block-returned.cpp
index af2cec776697..b45cf6335b90 100644
--- a/test/Analysis/stack-block-returned.cpp
+++ b/test/Analysis/stack-block-returned.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
typedef void (^bptr)(void);
diff --git a/test/Analysis/stackaddrleak.c b/test/Analysis/stackaddrleak.c
index 717f30964acd..a037d12fe40c 100644
--- a/test/Analysis/stackaddrleak.c
+++ b/test/Analysis/stackaddrleak.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -x c++ -Wno-bool-conversion %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -x c++ -Wno-bool-conversion %s
typedef __INTPTR_TYPE__ intptr_t;
char const *p;
diff --git a/test/Analysis/static_local.m b/test/Analysis/static_local.m
index dcd49e11a16c..daa7ef54c9f8 100644
--- a/test/Analysis/static_local.m
+++ b/test/Analysis/static_local.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -Wno-objc-root-class %s
// expected-no-diagnostics
// Test reasoning about static locals in ObjCMethods.
diff --git a/test/Analysis/stats.c b/test/Analysis/stats.c
index 5701dc71f5fa..eca83c0ad96e 100644
--- a/test/Analysis/stats.c
+++ b/test/Analysis/stats.c
@@ -1,5 +1,5 @@
// REQUIRES: asserts
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-stats %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-stats %s 2>&1 | FileCheck %s
void foo() {
int x;
diff --git a/test/Analysis/std-c-library-functions.c b/test/Analysis/std-c-library-functions.c
index 6b78a26d44bb..042b035f8bdf 100644
--- a/test/Analysis/std-c-library-functions.c
+++ b/test/Analysis/std-c-library-functions.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
-// RUN: %clang_cc1 -triple i686-unknown-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
-// RUN: %clang_cc1 -triple armv7-a15-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
-// RUN: %clang_cc1 -triple thumbv7-a15-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -triple i686-unknown-linux -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -triple armv7-a15-linux -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -triple thumbv7-a15-linux -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/std-c-library-functions.cpp b/test/Analysis/std-c-library-functions.cpp
index e6ac66bc81a3..00b341af5f92 100644
--- a/test/Analysis/std-c-library-functions.cpp
+++ b/test/Analysis/std-c-library-functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -analyze -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=unix.StdCLibraryFunctions,debug.ExprInspection -verify %s
// Test that we don't model functions with broken prototypes.
// Because they probably work differently as well.
diff --git a/test/Analysis/stream.c b/test/Analysis/stream.c
index 329a7823f2e5..7adf14be34d9 100644
--- a/test/Analysis/stream.c
+++ b/test/Analysis/stream.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.unix.Stream -analyzer-store region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.unix.Stream -analyzer-store region -verify %s
typedef __typeof__(sizeof(int)) size_t;
typedef struct _IO_FILE FILE;
diff --git a/test/Analysis/string-fail.c b/test/Analysis/string-fail.c
index ac5c6d057235..ff95ea9ee28f 100644
--- a/test/Analysis/string-fail.c
+++ b/test/Analysis/string-fail.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
// XFAIL: *
// This file is for tests that may eventually go into string.c, or may be
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index e541219d05a2..8ea2068c5613 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=alpha.security.taint,core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=alpha.security.taint,core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
diff --git a/test/Analysis/superclass.m b/test/Analysis/superclass.m
index 3102d1f35a7c..172935995389 100644
--- a/test/Analysis/superclass.m
+++ b/test/Analysis/superclass.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=osx.cocoa.MissingSuperCall -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=osx.cocoa.MissingSuperCall -verify -Wno-objc-root-class %s
// Define used Classes
@protocol NSObject
diff --git a/test/Analysis/svalbuilder-logic.c b/test/Analysis/svalbuilder-logic.c
index 9cf3f964bc0a..1595acb93569 100644
--- a/test/Analysis/svalbuilder-logic.c
+++ b/test/Analysis/svalbuilder-logic.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -verify %s
// expected-no-diagnostics
// Testing core functionality of the SValBuilder.
diff --git a/test/Analysis/switch-case.c b/test/Analysis/switch-case.c
index 08a61a07be26..08403937e019 100644
--- a/test/Analysis/switch-case.c
+++ b/test/Analysis/switch-case.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
void clang_analyzer_warnIfReached();
diff --git a/test/Analysis/symbol-reaper.c b/test/Analysis/symbol-reaper.c
index 362a22d4caf3..72fcc7e2b9df 100644
--- a/test/Analysis/symbol-reaper.c
+++ b/test/Analysis/symbol-reaper.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
void clang_analyzer_warnOnDeadSymbol(int);
diff --git a/test/Analysis/taint-diagnostic-visitor.c b/test/Analysis/taint-diagnostic-visitor.c
new file mode 100644
index 000000000000..50fc0b6a4e26
--- /dev/null
+++ b/test/Analysis/taint-diagnostic-visitor.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core -analyzer-output=text -verify %s
+
+// This file is for testing enhanced diagnostics produced by the GenericTaintChecker
+
+int scanf(const char *restrict format, ...);
+int system(const char *command);
+
+void taintDiagnostic()
+{
+ char buf[128];
+ scanf("%s", buf); // expected-note {{Taint originated here}}
+ system(buf); // expected-warning {{Untrusted data is passed to a system call}} // expected-note {{Untrusted data is passed to a system call (CERT/STR02-C. Sanitize data passed to complex subsystems)}}
+}
diff --git a/test/Analysis/taint-generic.c b/test/Analysis/taint-generic.c
index fe27070026bd..8efed66dacbf 100644
--- a/test/Analysis/taint-generic.c
+++ b/test/Analysis/taint-generic.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -Wno-format-security -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -Wno-format-security -verify %s
int scanf(const char *restrict format, ...);
int getchar(void);
@@ -169,6 +169,43 @@ void testSocket() {
sock = socket(AF_LOCAL, SOCK_STREAM, 0);
read(sock, buffer, 100);
execl(buffer, "filename", 0); // no-warning
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ // References to both buffer and &buffer as an argument should taint the argument
+ read(sock, &buffer, 100);
+ execl(buffer, "filename", 0); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+void testStruct() {
+ struct {
+ char buf[16];
+ int length;
+ } tainted;
+
+ char buffer[16];
+ int sock;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ read(sock, &tainted, sizeof(tainted));
+ __builtin_memcpy(buffer, tainted.buf, tainted.length); // expected-warning {{Untrusted data is used to specify the buffer size}}
+}
+
+void testStructArray() {
+ struct {
+ char buf[16];
+ struct {
+ int length;
+ } st[1];
+ } tainted;
+
+ char buffer[16];
+ int sock;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ read(sock, &tainted.buf[0], sizeof(tainted.buf));
+ read(sock, &tainted.st[0], sizeof(tainted.st));
+ // FIXME: tainted.st[0].length should be marked tainted
+ __builtin_memcpy(buffer, tainted.buf, tainted.st[0].length); // no-warning
}
int testDivByZero() {
diff --git a/test/Analysis/taint-tester.c b/test/Analysis/taint-tester.c
index 6287198eda45..1b59e7bc8e90 100644
--- a/test/Analysis/taint-tester.c
+++ b/test/Analysis/taint-tester.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-int-to-pointer-cast -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
+// RUN: %clang_analyze_cc1 -Wno-int-to-pointer-cast -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
#include "Inputs/system-header-simulator.h"
diff --git a/test/Analysis/taint-tester.cpp b/test/Analysis/taint-tester.cpp
index ca7b729f2691..23a92cc56d24 100644
--- a/test/Analysis/taint-tester.cpp
+++ b/test/Analysis/taint-tester.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
// expected-no-diagnostics
typedef struct _FILE FILE;
diff --git a/test/Analysis/taint-tester.m b/test/Analysis/taint-tester.m
index b5663ca02777..531c21b5faf8 100644
--- a/test/Analysis/taint-tester.m
+++ b/test/Analysis/taint-tester.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
// expected-no-diagnostics
#import <stdarg.h>
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index a9e455625957..372443bedffa 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -1,7 +1,7 @@
// RUN: rm -f %t
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true -std=c++98 %s > %t 2>&1
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true -std=c++98 %s > %t 2>&1
// RUN: FileCheck --input-file=%t -check-prefix=CXX98 -check-prefix=CHECK %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true -std=c++11 %s > %t 2>&1
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true -std=c++11 %s > %t 2>&1
// RUN: FileCheck --input-file=%t -check-prefix=CXX11 -check-prefix=CHECK %s
class A {
diff --git a/test/Analysis/templates.cpp b/test/Analysis/templates.cpp
index 131794a7c931..c1631e0db90c 100644
--- a/test/Analysis/templates.cpp
+++ b/test/Analysis/templates.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fblocks -analyzer-config c++-template-inlining=false -DNO_INLINE -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -fblocks -analyzer-config c++-template-inlining=false -DNO_INLINE -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/temporaries-callback-order.cpp b/test/Analysis/temporaries-callback-order.cpp
new file mode 100644
index 000000000000..df916cc4e767
--- /dev/null
+++ b/test/Analysis/temporaries-callback-order.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.AnalysisOrder -analyzer-config debug.AnalysisOrder:Bind=true -analyzer-config debug.AnalysisOrder:RegionChanges=true %s 2>&1 | FileCheck %s
+
+struct Super {
+ virtual void m();
+};
+struct Sub : Super {
+ virtual void m() {}
+};
+
+void testTemporaries() {
+ // This triggers RegionChanges twice:
+ // - Once for zero-initialization of the structure.
+ // - Once for creating a temporary region and copying the structure there.
+ // FIXME: This code shouldn't really produce the extra temporary, however
+ // that's how we behave for now.
+ Sub().m();
+}
+
+void seeIfCheckBindWorks() {
+ // This should trigger checkBind. The rest of the code shouldn't.
+ // This also triggers checkRegionChanges after that.
+ // Note that this function is analyzed first, so the messages would be on top.
+ int x = 1;
+}
+
+// seeIfCheckBindWorks():
+// CHECK: Bind
+// CHECK-NEXT: RegionChanges
+
+// testTemporaries():
+// CHECK-NEXT: RegionChanges
+// CHECK-NEXT: RegionChanges
+
+// Make sure there's no further output.
+// CHECK-NOT: Bind
+// CHECK-NOT: RegionChanges
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index 49cf070177fc..99851dd68539 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s -std=c++11
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s -std=c++11
extern bool clang_analyzer_eval(bool);
extern bool clang_analyzer_warnIfReached();
@@ -493,3 +493,40 @@ namespace PR16629 {
clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
}
}
+
+namespace PR32088 {
+ void testReturnFromStmtExprInitializer() {
+ // We shouldn't try to destroy the object pointed to by `obj' upon return.
+ const NonTrivial &obj = ({
+ return; // no-crash
+ NonTrivial(42);
+ });
+ }
+}
+
+namespace CopyToTemporaryCorrectly {
+class Super {
+public:
+ void m() {
+ mImpl();
+ }
+ virtual void mImpl() = 0;
+};
+class Sub : public Super {
+public:
+ Sub(const int &p) : j(p) {}
+ virtual void mImpl() override {
+ // Used to be undefined pointer dereference because we didn't copy
+ // the subclass data (j) to the temporary object properly.
+ (void)(j + 1); // no-warning
+ if (j != 22) {
+ clang_analyzer_warnIfReached(); // no-warning
+ }
+ }
+ const int &j;
+};
+void run() {
+ int i = 22;
+ Sub(i).m();
+}
+}
diff --git a/test/Analysis/test-after-div-zero.c b/test/Analysis/test-after-div-zero.c
index f34c4f7a3661..159c80c11d86 100644
--- a/test/Analysis/test-after-div-zero.c
+++ b/test/Analysis/test-after-div-zero.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c99 -Dbool=_Bool -analyze -analyzer-checker=core,alpha.core.TestAfterDivZero -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -x c++ -analyze -analyzer-checker=core,alpha.core.TestAfterDivZero -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -std=c99 -Dbool=_Bool -analyzer-checker=core,alpha.core.TestAfterDivZero -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -x c++ -analyzer-checker=core,alpha.core.TestAfterDivZero -analyzer-output=text -verify %s
int var;
diff --git a/test/Analysis/test-include-cpp.cpp b/test/Analysis/test-include-cpp.cpp
index 2ac5e11c997e..6998e3ccd669 100644
--- a/test/Analysis/test-include-cpp.cpp
+++ b/test/Analysis/test-include-cpp.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
#include "test-include-cpp.h"
diff --git a/test/Analysis/test-include.c b/test/Analysis/test-include.c
index 6aa80b96426c..20aa2447850b 100644
--- a/test/Analysis/test-include.c
+++ b/test/Analysis/test-include.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
#include "test-include.h"
#define DIVYX(X,Y) Y/X
diff --git a/test/Analysis/test-objc-non-nil-return-value-checker.m b/test/Analysis/test-objc-non-nil-return-value-checker.m
index 8b1e6a5054a5..2a9063624639 100644
--- a/test/Analysis/test-objc-non-nil-return-value-checker.m
+++ b/test/Analysis/test-objc-non-nil-return-value-checker.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.NonNilReturnValue,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=osx.cocoa.NonNilReturnValue,debug.ExprInspection -verify %s
typedef unsigned int NSUInteger;
typedef signed char BOOL;
diff --git a/test/Analysis/test-variably-modified-types.c b/test/Analysis/test-variably-modified-types.c
index a833434228d1..1df57affad41 100644
--- a/test/Analysis/test-variably-modified-types.c
+++ b/test/Analysis/test-variably-modified-types.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyze-function=testVariablyModifiedTypes -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyze-function=testVariablyModifiedTypes -verify %s
// Test that we process variably modified type correctly - the call graph construction should pick up function_with_bug while recursively visiting test_variably_modifiable_types.
unsigned getArraySize(int *x) {
diff --git a/test/Analysis/traversal-algorithm.mm b/test/Analysis/traversal-algorithm.mm
index 8a3dc8b3a222..bdf576063d65 100644
--- a/test/Analysis/traversal-algorithm.mm
+++ b/test/Analysis/traversal-algorithm.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpTraversal -analyzer-max-loop 4 -std=c++11 %s | FileCheck -check-prefix=DFS %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpTraversal -analyzer-max-loop 4 -std=c++11 %s | FileCheck -check-prefix=DFS %s
int a();
int b();
diff --git a/test/Analysis/traversal-begin-end-function.c b/test/Analysis/traversal-begin-end-function.c
index 810ce1d2a529..9d46f26ce8f9 100644
--- a/test/Analysis/traversal-begin-end-function.c
+++ b/test/Analysis/traversal-begin-end-function.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.DumpTraversal %s | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.DumpTraversal %s | FileCheck %s
void inline_callee(int i);
diff --git a/test/Analysis/traversal-path-unification.c b/test/Analysis/traversal-path-unification.c
index 3bf6df731c22..28a15110f903 100644
--- a/test/Analysis/traversal-path-unification.c
+++ b/test/Analysis/traversal-path-unification.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.DumpTraversal %s | FileCheck %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.DumpTraversal -DUSE_EXPR %s | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.DumpTraversal %s | FileCheck %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.DumpTraversal -DUSE_EXPR %s | FileCheck %s
int a();
int b();
diff --git a/test/Analysis/ubigraph-viz.cpp b/test/Analysis/ubigraph-viz.cpp
index 0cb9bd6d8929..228dd660c7ff 100644
--- a/test/Analysis/ubigraph-viz.cpp
+++ b/test/Analysis/ubigraph-viz.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.API -analyzer-viz-egraph-ubigraph -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API -analyzer-viz-egraph-ubigraph -verify %s
// expected-no-diagnostics
int f(int x) {
diff --git a/test/Analysis/undef-buffers.c b/test/Analysis/undef-buffers.c
index 1581b2b8cbb2..d5802fb8c640 100644
--- a/test/Analysis/undef-buffers.c
+++ b/test/Analysis/undef-buffers.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix,core.uninitialized -analyzer-store=region -verify -analyzer-config unix:Optimistic=true %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,core.uninitialized -analyzer-store=region -verify -analyzer-config unix:Optimistic=true %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
diff --git a/test/Analysis/uninit-const.c b/test/Analysis/uninit-const.c
index 9e42d23214de..9a6529a772a7 100644
--- a/test/Analysis/uninit-const.c
+++ b/test/Analysis/uninit-const.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc,core,alpha.core.CallAndMessageUnInitRefArg -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc,core,alpha.core.CallAndMessageUnInitRefArg -analyzer-output=text -verify %s
// Passing uninitialized const data to function
#include "Inputs/system-header-simulator.h"
@@ -24,16 +24,16 @@ void doStuff_variadic(const int *u, ...){};
void f_1(void) {
int t;
int* tp = &t; // expected-note {{'tp' initialized here}}
- doStuff_pointerToConstInt(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_1_1(void) {
int t;
int* tp1 = &t;
int* tp2 = tp1; // expected-note {{'tp2' initialized here}}
- doStuff_pointerToConstInt(tp2); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_pointerToConstInt(tp2); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
@@ -45,8 +45,8 @@ void f_2(void) {
int t;
int* p = f_2_sub(&t);
int* tp = p; // expected-note {{'tp' initialized here}}
- doStuff_pointerToConstInt(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
int z;
@@ -62,14 +62,14 @@ void f_4(void) {
void f_5(void) {
int ta[5];
int* tp = ta; // expected-note {{'tp' initialized here}}
- doStuff_pointerToConstInt(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_5_1(void) {
int ta[5]; // expected-note {{'ta' initialized here}}
- doStuff_pointerToConstInt(ta); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_pointerToConstInt(ta); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_6(void) {
@@ -92,27 +92,27 @@ void f_7(void) {
void f_8(void) {
int g; // expected-note {{'g' declared without an initial value}}
- doStuff2(g); // expected-warning {{Function call argument is an uninitialized value}}
- // expected-note@-1 {{Function call argument is an uninitialized value}}
+ doStuff2(g); // expected-warning {{1st function call argument is an uninitialized value}}
+ // expected-note@-1 {{1st function call argument is an uninitialized value}}
}
void f_9(void) {
int a[6];
int const *ptau = a; // expected-note {{'ptau' initialized here}}
- doStuff_arrayOfConstInt(ptau); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_arrayOfConstInt(ptau); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_10(void) {
int a[6]; // expected-note {{'a' initialized here}}
- doStuff_arrayOfConstInt(a); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_arrayOfConstInt(a); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_11(void) {
int t[10]; //expected-note {{'t' initialized here}}
- doStuff_constStaticSizedArray(t); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_constStaticSizedArray(t); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_12(void) {
@@ -126,8 +126,8 @@ int f_malloc_1(void) {
ptr = (int *)malloc(sizeof(int)); // expected-note {{Value assigned to 'ptr'}}
- doStuff_pointerToConstInt(ptr); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_pointerToConstInt(ptr); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
free(ptr);
return 0;
}
@@ -148,16 +148,16 @@ void f_variadic_unp_unv(void) {
int t;
int v;
int* tp = &t; // expected-note {{'tp' initialized here}}
- doStuff_variadic(tp,v); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_variadic(tp,v); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
// uninit pointer, init val
void f_variadic_unp_inv(void) {
int t;
int v = 3;
int* tp = &t; // expected-note {{'tp' initialized here}}
- doStuff_variadic(tp,v); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_variadic(tp,v); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
// init pointer, uninit val
@@ -165,8 +165,8 @@ void f_variadic_inp_unv(void) {
int t=5;
int v; // expected-note {{'v' declared without an initial value}}
int* tp = &t;
- doStuff_variadic(tp,v);// expected-warning {{Function call argument is an uninitialized value}}
- // expected-note@-1 {{Function call argument is an uninitialized value}}
+ doStuff_variadic(tp,v);// expected-warning {{2nd function call argument is an uninitialized value}}
+ // expected-note@-1 {{2nd function call argument is an uninitialized value}}
}
// init pointer, init val
@@ -192,8 +192,8 @@ void f_variadic_unp_inp(void) {
int u=3;
int *vp = &u ;
int *tp = &t; // expected-note {{'tp' initialized here}}
- doStuff_variadic(tp,vp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_variadic(tp,vp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
//init pointer, uninit pointer
@@ -211,6 +211,6 @@ void f_variadic_unp_unp(void) {
int u;
int *vp = &u ;
int *tp = &t; // expected-note {{'tp' initialized here}}
- doStuff_variadic(tp,vp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_variadic(tp,vp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
diff --git a/test/Analysis/uninit-const.cpp b/test/Analysis/uninit-const.cpp
index 56bfa08e4176..75e932a77ced 100644
--- a/test/Analysis/uninit-const.cpp
+++ b/test/Analysis/uninit-const.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=cplusplus.NewDelete,core,alpha.core.CallAndMessageUnInitRefArg -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.NewDelete,core,alpha.core.CallAndMessageUnInitRefArg -analyzer-output=text -verify %s
// Passing uninitialized const data to unknown function
#include "Inputs/system-header-simulator-cxx.h"
@@ -66,8 +66,8 @@ void f6_2(void) {
int &p = t;
int &s = p;
int &q = s; //expected-note {{'q' initialized here}}
- doStuff6(q); //expected-warning {{Function call argument is an uninitialized value}}
- //expected-note@-1 {{Function call argument is an uninitialized value}}
+ doStuff6(q); //expected-warning {{1st function call argument is an uninitialized value}}
+ //expected-note@-1 {{1st function call argument is an uninitialized value}}
}
void doStuff6_3(int& q_, int *ptr_) {}
@@ -78,15 +78,15 @@ void f6_3(void) {
int &p = t;
int &s = p;
int &q = s;
- doStuff6_3(q,ptr); //expected-warning {{Function call argument is an uninitialized value}}
- //expected-note@-1 {{Function call argument is an uninitialized value}}
+ doStuff6_3(q,ptr); //expected-warning {{2nd function call argument is an uninitialized value}}
+ //expected-note@-1 {{2nd function call argument is an uninitialized value}}
}
void f6(void) {
int k; // expected-note {{'k' declared without an initial value}}
- doStuff6(k); // expected-warning {{Function call argument is an uninitialized value}}
- // expected-note@-1 {{Function call argument is an uninitialized value}}
+ doStuff6(k); // expected-warning {{1st function call argument is an uninitialized value}}
+ // expected-note@-1 {{1st function call argument is an uninitialized value}}
}
@@ -95,15 +95,15 @@ void f6(void) {
void f5(void) {
int t;
int* tp = &t; // expected-note {{'tp' initialized here}}
- doStuff_uninit(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_uninit(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f4(void) {
int y; // expected-note {{'y' declared without an initial value}}
- doStuff4(y); // expected-warning {{Function call argument is an uninitialized value}}
- // expected-note@-1 {{Function call argument is an uninitialized value}}
+ doStuff4(y); // expected-warning {{1st function call argument is an uninitialized value}}
+ // expected-note@-1 {{1st function call argument is an uninitialized value}}
}
void f3(void) {
@@ -123,6 +123,6 @@ void f1(void) {
void f_uninit(void) {
int x;
- doStuff_uninit(&x); // expected-warning {{Function call argument is a pointer to uninitialized value}}
- // expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
+ doStuff_uninit(&x); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
+ // expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m
index 19fdf611c865..8454137967f6 100644
--- a/test/Analysis/uninit-msg-expr.m
+++ b/test/Analysis/uninit-msg-expr.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
@@ -52,5 +52,5 @@ unsigned f2() {
void f3() {
NSMutableArray *aArray = [NSArray array];
NSString *aString;
- [aArray addObject:aString]; // expected-warning {{Argument in message expression is an uninitialized value}}
+ [aArray addObject:aString]; // expected-warning {{1st argument in message expression is an uninitialized value}}
}
diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m
index c18116f21ae5..d735f17317cf 100644
--- a/test/Analysis/uninit-ps-rdar6145427.m
+++ b/test/Analysis/uninit-ps-rdar6145427.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -analyzer-store=region %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -analyzer-store=region %s
// Delta-Debugging reduced preamble.
typedef signed char BOOL;
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index 87256b3b4b1b..18010f240d3d 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core -verify %s
struct s {
int data;
diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c
index ad40b15502e4..ee25d9d9a602 100644
--- a/test/Analysis/uninit-vals-ps.c
+++ b/test/Analysis/uninit-vals-ps.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
struct FPRec {
void (*my_func)(int * x);
@@ -14,7 +14,7 @@ int f1_a(struct FPRec* foo) {
int f1_b() {
int x;
- return bar(x)+1; // expected-warning{{Function call argument is an uninitialized value}}
+ return bar(x)+1; // expected-warning{{1st function call argument is an uninitialized value}}
}
int f2() {
@@ -57,6 +57,12 @@ int f5(void) {
return s.x; // no-warning
}
+void f6(int x) {
+ int a[20];
+ if (x == 25) {}
+ if (a[x] == 123) {} // expected-warning{{The left operand of '==' is a garbage value due to array index out of bounds}}
+}
+
int ret_uninit() {
int i;
int *p = &i;
diff --git a/test/Analysis/uninit-vals-union.c b/test/Analysis/uninit-vals-union.c
index 927dfa2e5979..b433e7b0ef62 100644
--- a/test/Analysis/uninit-vals-union.c
+++ b/test/Analysis/uninit-vals-union.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.builtin -analyzer-store=region -verify -Wno-unused %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.builtin -analyzer-store=region -verify -Wno-unused %s
typedef union {
int y;
diff --git a/test/Analysis/uninit-vals.cpp b/test/Analysis/uninit-vals.cpp
index 387c3754dae4..5ab1348ae5c0 100644
--- a/test/Analysis/uninit-vals.cpp
+++ b/test/Analysis/uninit-vals.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.builtin -verify -DCHECK_FOR_CRASH %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.builtin -verify -DCHECK_FOR_CRASH %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
#ifdef CHECK_FOR_CRASH
// expected-no-diagnostics
@@ -27,7 +27,7 @@ void foo() {
// case with undefined values, too.
c1.b.a = c2->b.a;
#else
- c1.b.a = c2->b.a; // expected-warning{{Function call argument is an uninitialized value}}
+ c1.b.a = c2->b.a; // expected-warning{{1st function call argument is an uninitialized value}}
#endif
}
}
diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
index 72b673980017..7c18dee97606 100644
--- a/test/Analysis/uninit-vals.m
+++ b/test/Analysis/uninit-vals.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
typedef unsigned int NSUInteger;
typedef __typeof__(sizeof(int)) size_t;
diff --git a/test/Analysis/unions-region.m b/test/Analysis/unions-region.m
index 636198ad0594..bad159fe8123 100644
--- a/test/Analysis/unions-region.m
+++ b/test/Analysis/unions-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region %s -verify
// expected-no-diagnostics
//===-- unions-region.m ---------------------------------------------------===//
diff --git a/test/Analysis/unions.cpp b/test/Analysis/unions.cpp
index f363ab81ae72..2758cdaa26b3 100644
--- a/test/Analysis/unions.cpp
+++ b/test/Analysis/unions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection %s -verify
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection %s -verify
extern void clang_analyzer_eval(bool);
extern "C" char *strdup(const char *s);
diff --git a/test/Analysis/unix-api.c b/test/Analysis/unix-api.c
index 24b145d3d3d9..64ff3c0fccf4 100644
--- a/test/Analysis/unix-api.c
+++ b/test/Analysis/unix-api.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.API -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API -verify %s
#ifndef O_RDONLY
#define O_RDONLY 0
diff --git a/test/Analysis/unix-api.cpp b/test/Analysis/unix-api.cpp
index 1c8f99632c07..2b07d8807c1f 100644
--- a/test/Analysis/unix-api.cpp
+++ b/test/Analysis/unix-api.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.API -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API -verify %s
extern "C" {
#ifndef O_RDONLY
#define O_RDONLY 0
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index b14457845895..3eccd51d2c60 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,unix.API,osx.API %s -analyzer-store=region -analyzer-output=plist -analyzer-eagerly-assume -analyzer-config faux-bodies=true -analyzer-config path-diagnostics-alternate=false -fblocks -verify -o %t.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,unix.API,osx.API %s -analyzer-store=region -analyzer-output=plist -analyzer-eagerly-assume -analyzer-config faux-bodies=true -analyzer-config path-diagnostics-alternate=false -fblocks -verify -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
// RUN: mkdir -p %t.dir
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.API,osx.API -analyzer-output=html -analyzer-config faux-bodies=true -fblocks -o %t.dir %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API,osx.API -analyzer-output=html -analyzer-config faux-bodies=true -fblocks -o %t.dir %s
// RUN: rm -fR %t.dir
struct _opaque_pthread_once_t {
long __sig;
diff --git a/test/Analysis/unreachable-code-path.c b/test/Analysis/unreachable-code-path.c
index 4ddfb21f0a0f..ff58587be2da 100644
--- a/test/Analysis/unreachable-code-path.c
+++ b/test/Analysis/unreachable-code-path.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,alpha.deadcode.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,deadcode.DeadStores,alpha.deadcode.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
extern void foo(int a);
diff --git a/test/Analysis/unsupported-types.c b/test/Analysis/unsupported-types.c
new file mode 100644
index 000000000000..9233095e4211
--- /dev/null
+++ b/test/Analysis/unsupported-types.c
@@ -0,0 +1,31 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -triple x86_64-unknown-linux -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -triple powerpc64-linux-gnu -verify %s
+
+#define _Complex_I (__extension__ 1.0iF)
+
+void clang_analyzer_eval(int);
+
+void complex_float(double _Complex x, double _Complex y) {
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ if (x != 1.0 + 3.0 * _Complex_I && y != 1.0 - 4.0 * _Complex_I)
+ return
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x + y == 2.0 - 1.0 * _Complex_I); // expected-warning{{UNKNOWN}}
+}
+
+void complex_int(int _Complex x, int _Complex y) {
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ if (x != 1.0 + 3.0 * _Complex_I && y != 1.0 - 4.0 * _Complex_I)
+ return
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x + y == 2.0 - 1.0 * _Complex_I); // expected-warning{{UNKNOWN}}
+}
+
+void longdouble_float(long double x, long double y) {
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ if (x != 0.0L && y != 1.0L)
+ return
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x + y == 1.0L); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m
index f04132ba4570..8f12d9b18a7d 100644
--- a/test/Analysis/unused-ivars.m
+++ b/test/Analysis/unused-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=osx.cocoa.UnusedIvars -verify -Wno-objc-root-class %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=osx.cocoa.UnusedIvars -verify -Wno-objc-root-class %s
//===--- BEGIN: Delta-debugging reduced headers. --------------------------===//
diff --git a/test/Analysis/valist-as-lazycompound.c b/test/Analysis/valist-as-lazycompound.c
new file mode 100644
index 000000000000..2fbd4cb76f48
--- /dev/null
+++ b/test/Analysis/valist-as-lazycompound.c
@@ -0,0 +1,21 @@
+// RUN: %clang_analyze_cc1 -triple gcc-linaro-arm-linux-gnueabihf -analyzer-checker=core,valist.Uninitialized,valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s
+// expected-no-diagnostics
+
+typedef unsigned int size_t;
+typedef __builtin_va_list __gnuc_va_list;
+typedef __gnuc_va_list va_list;
+
+extern int vsprintf(char *__restrict __s,
+ const char *__restrict __format, __gnuc_va_list
+ __arg);
+
+void _dprintf(const char *function, int flen, int line, int level,
+ const char *prefix, const char *fmt, ...) {
+ char raw[10];
+ int err;
+ va_list ap;
+
+ __builtin_va_start(ap, fmt);
+ err = vsprintf(raw, fmt, ap);
+ __builtin_va_end(ap);
+}
diff --git a/test/Analysis/valist-uninitialized-no-undef.c b/test/Analysis/valist-uninitialized-no-undef.c
new file mode 100644
index 000000000000..528ac86c1421
--- /dev/null
+++ b/test/Analysis/valist-uninitialized-no-undef.c
@@ -0,0 +1,40 @@
+// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,valist.Uninitialized,valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s
+
+#include "Inputs/system-header-simulator-for-valist.h"
+
+// This is called in call_inlined_uses_arg(),
+// and the warning is generated during the analysis of call_inlined_uses_arg().
+void inlined_uses_arg(va_list arg) {
+ (void)va_arg(arg, int); // expected-warning{{va_arg() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_arg() is called on an uninitialized va_list}}
+}
+
+void call_inlined_uses_arg(int fst, ...) {
+ va_list va;
+ inlined_uses_arg(va); // expected-note{{Calling 'inlined_uses_arg'}}
+}
+
+void f6(va_list *fst, ...) {
+ va_start(*fst, fst);
+ // FIXME: There should be no warning for this.
+ (void)va_arg(*fst, int); // expected-warning{{va_arg() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_arg() is called on an uninitialized va_list}}
+ va_end(*fst);
+}
+
+void call_vprintf_bad(int isstring, ...) {
+ va_list va;
+ vprintf(isstring ? "%s" : "%d", va); // expected-warning{{Function 'vprintf' is called with an uninitialized va_list argument}}
+ // expected-note@-1{{Function 'vprintf' is called with an uninitialized va_list argument}}
+ // expected-note@-2{{Assuming 'isstring' is 0}}
+ // expected-note@-3{{'?' condition is false}}
+}
+
+void call_vsprintf_bad(char *buffer, ...) {
+ va_list va;
+ va_start(va, buffer); // expected-note{{Initialized va_list}}
+ va_end(va); // expected-note{{Ended va_list}}
+ vsprintf(buffer, "%s %d %d %lf %03d", va); // expected-warning{{Function 'vsprintf' is called with an uninitialized va_list argument}}
+ // expected-note@-1{{Function 'vsprintf' is called with an uninitialized va_list argument}}
+}
+
diff --git a/test/Analysis/valist-uninitialized.c b/test/Analysis/valist-uninitialized.c
index b1f11d138fec..19308537e02c 100644
--- a/test/Analysis/valist-uninitialized.c
+++ b/test/Analysis/valist-uninitialized.c
@@ -1,17 +1,20 @@
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,alpha.valist.Uninitialized,alpha.valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple hexagon-unknown-linux -analyzer-checker=core,valist.Uninitialized,valist.CopyToSelf -analyzer-disable-checker=core.CallAndMessage -analyzer-output=text -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,valist.Uninitialized,valist.CopyToSelf -analyzer-disable-checker=core.CallAndMessage -analyzer-output=text -analyzer-store=region -verify %s
#include "Inputs/system-header-simulator-for-valist.h"
void f1(int fst, ...) {
va_list va;
- (void)va_arg(va, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}}
+ (void)va_arg(va, int); // expected-warning{{va_arg() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_arg() is called on an uninitialized va_list}}
}
int f2(int fst, ...) {
va_list va;
va_start(va, fst); // expected-note{{Initialized va_list}}
va_end(va); // expected-note{{Ended va_list}}
- return va_arg(va, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}}
+ return va_arg(va, int); // expected-warning{{va_arg() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_arg() is called on an uninitialized va_list}}
}
void f3(int fst, ...) {
@@ -25,11 +28,13 @@ void f3(int fst, ...) {
void f4(int cond, ...) {
va_list va;
- if (cond) { // expected-note{{Assuming 'cond' is 0}} expected-note{{Taking false branch}}
+ if (cond) { // expected-note{{Assuming 'cond' is 0}}
+ // expected-note@-1{{Taking false branch}}
va_start(va, cond);
(void)va_arg(va,int);
}
- va_end(va); //expected-warning{{va_end() is called on an uninitialized va_list}} expected-note{{va_end() is called on an uninitialized va_list}}
+ va_end(va); //expected-warning{{va_end() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_end() is called on an uninitialized va_list}}
}
void f5(va_list fst, ...) {
@@ -38,13 +43,6 @@ void f5(va_list fst, ...) {
va_end(fst);
} // no-warning
-//FIXME: this should not cause a warning
-void f6(va_list *fst, ...) {
- va_start(*fst, fst);
- (void)va_arg(*fst, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}}
- va_end(*fst);
-}
-
void f7(int *fst, ...) {
va_list x;
va_list *y = &x;
@@ -58,8 +56,9 @@ void f8(int *fst, ...) {
va_list *y = &x;
va_start(*y,fst); // expected-note{{Initialized va_list}}
va_end(x); // expected-note{{Ended va_list}}
- (void)va_arg(*y, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}}
-} // no-warning
+ (void)va_arg(*y, int); //expected-warning{{va_arg() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_arg() is called on an uninitialized va_list}}
+}
// This only contains problems which are handled by varargs.Unterminated.
void reinit(int *fst, ...) {
@@ -87,48 +86,56 @@ void reinit3(int *fst, ...) {
va_start(va, fst); // expected-note{{Initialized va_list}}
(void)va_arg(va, int);
va_end(va); // expected-note{{Ended va_list}}
- (void)va_arg(va, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}}
+ (void)va_arg(va, int); //expected-warning{{va_arg() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_arg() is called on an uninitialized va_list}}
}
void copyself(int fst, ...) {
va_list va;
va_start(va, fst); // expected-note{{Initialized va_list}}
- va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} expected-note{{va_list 'va' is copied onto itself}}
+ va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}}
+ // expected-note@-1{{va_list 'va' is copied onto itself}}
va_end(va);
-} // no-warning
+}
void copyselfUninit(int fst, ...) {
va_list va;
- va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} expected-note{{va_list 'va' is copied onto itself}}
-} // no-warning
+ va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}}
+ // expected-note@-1{{va_list 'va' is copied onto itself}}
+}
void copyOverwrite(int fst, ...) {
va_list va, va2;
va_start(va, fst); // expected-note{{Initialized va_list}}
- va_copy(va, va2); // expected-warning{{Initialized va_list 'va' is overwritten by an uninitialized one}} expected-note{{Initialized va_list 'va' is overwritten by an uninitialized one}}
-} // no-warning
+ va_copy(va, va2); // expected-warning{{Initialized va_list 'va' is overwritten by an uninitialized one}}
+ // expected-note@-1{{Initialized va_list 'va' is overwritten by an uninitialized one}}
+}
void copyUnint(int fst, ...) {
va_list va, va2;
- va_copy(va, va2); // expected-warning{{Uninitialized va_list is copied}} expected-note{{Uninitialized va_list is copied}}
+ va_copy(va, va2); // expected-warning{{Uninitialized va_list is copied}}
+ // expected-note@-1{{Uninitialized va_list is copied}}
}
void g1(int fst, ...) {
va_list va;
- va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} expected-note{{va_end() is called on an uninitialized va_list}}
+ va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_end() is called on an uninitialized va_list}}
}
void g2(int fst, ...) {
va_list va;
va_start(va, fst); // expected-note{{Initialized va_list}}
va_end(va); // expected-note{{Ended va_list}}
- va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} expected-note{{va_end() is called on an uninitialized va_list}}
+ va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_end() is called on an uninitialized va_list}}
}
void is_sink(int fst, ...) {
va_list va;
- va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} expected-note{{va_end() is called on an uninitialized va_list}}
- *((volatile int *)0) = 1; //no-warning
+ va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}}
+ // expected-note@-1{{va_end() is called on an uninitialized va_list}}
+ *((volatile int *)0) = 1;
}
// NOTE: this is invalid, as the man page of va_end requires that "Each invocation of va_start()
@@ -141,17 +148,6 @@ void uses_arg(va_list arg) {
(void)va_arg(arg, int);
} //no-warning
-// This is the same function as the previous one, but it is called in call_uses_arg2(),
-// and the warning is generated during the analysis of call_uses_arg2().
-void inlined_uses_arg(va_list arg) {
- (void)va_arg(arg, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}}
-}
-
-void call_inlined_uses_arg(int fst, ...) {
- va_list va;
- inlined_uses_arg(va); // expected-note{{Calling 'inlined_uses_arg'}}
-}
-
void call_vprintf_ok(int isstring, ...) {
va_list va;
va_start(va, isstring);
@@ -159,20 +155,24 @@ void call_vprintf_ok(int isstring, ...) {
va_end(va);
} //no-warning
-void call_vprintf_bad(int isstring, ...) {
+void call_some_other_func(int n, ...) {
va_list va;
- vprintf(isstring ? "%s" : "%d", va); //expected-warning{{Function 'vprintf' is called with an uninitialized va_list argument}} expected-note{{Function 'vprintf' is called with an uninitialized va_list argument}} expected-note{{Assuming 'isstring' is 0}} expected-note{{'?' condition is false}}
-}
+ some_library_function(n, va);
+} //no-warning
-void call_vsprintf_bad(char *buffer, ...) {
- va_list va;
- va_start(va, buffer); // expected-note{{Initialized va_list}}
- va_end(va); // expected-note{{Ended va_list}}
- vsprintf(buffer, "%s %d %d %lf %03d", va); //expected-warning{{Function 'vsprintf' is called with an uninitialized va_list argument}} expected-note{{Function 'vsprintf' is called with an uninitialized va_list argument}}
+void inlined_uses_arg_good(va_list arg) {
+ (void)va_arg(arg, int);
}
-void call_some_other_func(int n, ...) {
+void call_inlined_uses_arg_good(int fst, ...) {
va_list va;
- some_library_function(n, va);
-} //no-warning
+ va_start(va, fst);
+ inlined_uses_arg_good(va);
+ va_end(va);
+}
+void va_copy_test(va_list arg) {
+ va_list dst;
+ va_copy(dst, arg);
+ va_end(dst);
+}
diff --git a/test/Analysis/valist-unterminated.c b/test/Analysis/valist-unterminated.c
index 63ee992b2894..e19c6761784c 100644
--- a/test/Analysis/valist-unterminated.c
+++ b/test/Analysis/valist-unterminated.c
@@ -1,11 +1,13 @@
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,alpha.valist.Unterminated,alpha.valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple hexagon-unknown-linux -analyzer-checker=core,valist.Unterminated,valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,valist.Unterminated,valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s
#include "Inputs/system-header-simulator-for-valist.h"
void f1(int fst, ...) {
va_list va;
va_start(va, fst); // expected-note{{Initialized va_list}}
- return; // expected-warning{{Initialized va_list 'va' is leaked}} expected-note{{Initialized va_list 'va' is leaked}}
+ return; // expected-warning{{Initialized va_list 'va' is leaked}}
+ // expected-note@-1{{Initialized va_list 'va' is leaked}}
}
void f2(int fst, ...) {
@@ -13,37 +15,42 @@ void f2(int fst, ...) {
va_start(va, fst); // expected-note{{Initialized va_list}}
va_end(va); // expected-note{{Ended va_list}}
va_start(va, fst); // expected-note{{Initialized va_list}}
-} // expected-warning{{Initialized va_list 'va' is leaked}} expected-note{{Initialized va_list 'va' is leaked}}}
+} // expected-warning{{Initialized va_list 'va' is leaked}}
+ // expected-note@-1{{Initialized va_list 'va' is leaked}}
void f3(int fst, ...) {
va_list va, va2;
va_start(va, fst);
va_copy(va2, va); // expected-note{{Initialized va_list}}
- va_end(va); // expected-warning{{Initialized va_list 'va2' is leaked}} expected-note{{Initialized va_list 'va2' is leaked}}
+ va_end(va); // expected-warning{{Initialized va_list 'va2' is leaked}}
+ // expected-note@-1{{Initialized va_list 'va2' is leaked}}
}
void f4(va_list *fst, ...) {
va_start(*fst, fst); // expected-note{{Initialized va_list}}
- return; // expected-warning{{Initialized va_list is leaked}} expected-note{{Initialized va_list is leaked}}
+ return; // expected-warning{{Initialized va_list is leaked}}
+ // expected-note@-1{{Initialized va_list is leaked}}
}
void f5(va_list fst, ...) {
- va_start(fst, fst);
- //FIXME: this should cause a warning
-} // no-warning
+ va_start(fst, fst); // expected-note{{Initialized va_list}}
+} // expected-warning{{Initialized va_list}}
+ // expected-note@-1{{Initialized va_list}}
void f6(va_list *fst, ...) {
va_start(*fst, fst); // expected-note{{Initialized va_list}}
(void)va_arg(*fst, int);
//FIXME: this should NOT cause a warning
- va_end(*fst); // expected-warning{{Initialized va_list is leaked}} expected-note{{Initialized va_list is leaked}}
+ va_end(*fst); // expected-warning{{Initialized va_list is leaked}}
+ // expected-note@-1{{Initialized va_list is leaked}}
}
void f7(int *fst, ...) {
va_list x;
va_list *y = &x;
va_start(*y,fst); // expected-note{{Initialized va_list}}
-} // expected-warning{{Initialized va_list 'x' is leaked}} expected-note{{Initialized va_list 'x' is leaked}}
+} // expected-warning{{Initialized va_list 'x' is leaked}}
+ // expected-note@-1{{Initialized va_list 'x' is leaked}}
void f8(int *fst, ...) {
va_list x;
@@ -54,9 +61,12 @@ void f8(int *fst, ...) {
void reinit(int *fst, ...) {
va_list va;
- va_start(va, fst); // expected-note{{Initialized va_list}} expected-note{{Initialized va_list}}
- va_start(va, fst); // expected-warning{{Initialized va_list 'va' is initialized again}} expected-note{{Initialized va_list 'va' is initialized again}}
-} // expected-warning{{Initialized va_list 'va' is leaked}} expected-note{{Initialized va_list 'va' is leaked}}
+ va_start(va, fst); // expected-note{{Initialized va_list}}
+ // expected-note@-1{{Initialized va_list}}
+ va_start(va, fst); // expected-warning{{Initialized va_list 'va' is initialized again}}
+ // expected-note@-1{{Initialized va_list 'va' is initialized again}}
+} // expected-warning{{Initialized va_list 'va' is leaked}}
+ // expected-note@-1{{Initialized va_list 'va' is leaked}}
void reinitOk(int *fst, ...) {
va_list va;
@@ -69,20 +79,23 @@ void reinitOk(int *fst, ...) {
void copyself(int fst, ...) {
va_list va;
va_start(va, fst); // expected-note{{Initialized va_list}}
- va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} expected-note{{va_list 'va' is copied onto itself}}
+ va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}}
+ // expected-note@-1{{va_list 'va' is copied onto itself}}
va_end(va);
-} // no-warning
+}
void copyselfUninit(int fst, ...) {
va_list va;
- va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} expected-note{{va_list 'va' is copied onto itself}}
-} // no-warning
+ va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}}
+ // expected-note@-1{{va_list 'va' is copied onto itself}}
+}
void copyOverwrite(int fst, ...) {
va_list va, va2;
va_start(va, fst); // expected-note{{Initialized va_list}}
- va_copy(va, va2); // expected-warning{{Initialized va_list 'va' is overwritten by an uninitialized one}} expected-note{{Initialized va_list 'va' is overwritten by an uninitialized one}}
-} // no-warning
+ va_copy(va, va2); // expected-warning{{Initialized va_list 'va' is overwritten by an uninitialized one}}
+ // expected-note@-1{{Initialized va_list 'va' is overwritten by an uninitialized one}}
+}
//This only generates a warning for the valist.Uninitialized checker
void copyUnint(int fst, ...) {
@@ -94,20 +107,27 @@ void recopy(int fst, ...) {
va_list va, va2;
va_start(va, fst);
va_copy(va2, va); // expected-note{{Initialized va_list}}
- va_copy(va2, va); // expected-warning{{Initialized va_list 'va2' is initialized again}} expected-note{{Initialized va_list 'va2' is initialized again}}
+ va_copy(va2, va); // expected-warning{{Initialized va_list 'va2' is initialized again}}
+ // expected-note@-1{{Initialized va_list 'va2' is initialized again}}
va_end(va);
va_end(va2);
-} //no-warning
+}
void doublemsg(int fst, ...) {
va_list va, va2;
- va_start(va, fst), va_start(va2, fst); // expected-warning{{Initialized va_list 'va' is leaked}} expected-warning{{Initialized va_list 'va2' is leaked}} expected-note{{Initialized va_list}} expected-note{{Initialized va_list}} expected-note{{Initialized va_list}} expected-note{{Initialized va_list 'va' is leaked}}
+ va_start(va, fst), va_start(va2, fst); // expected-warning{{Initialized va_list 'va' is leaked}}
+ // expected-warning@-1{{Initialized va_list 'va2' is leaked}}
+ // expected-note@-2{{Initialized va_list}}
+ // expected-note@-3{{Initialized va_list}}
+ // expected-note@-4{{Initialized va_list}}
+ // expected-note@-5{{Initialized va_list 'va' is leaked}}
}
void in_array(int fst, ...) {
va_list va_array[8];
va_start(va_array[3], fst); // expected-note{{Initialized va_list}}
-} // expected-warning{{Initialized va_list 'va_array[3]' is leaked}} expected-note{{Initialized va_list 'va_array[3]' is leaked}}
+} // expected-warning{{Initialized va_list 'va_array[3]' is leaked}}
+ // expected-note@-1{{Initialized va_list 'va_array[3]' is leaked}}
struct containing_a_valist {
va_list vafield;
@@ -117,12 +137,14 @@ struct containing_a_valist {
void in_struct(int fst, ...) {
struct containing_a_valist s;
va_start(s.vafield, fst); // expected-note{{Initialized va_list}}
-} // expected-warning{{Initialized va_list 's.vafield' is leaked}} expected-note{{Initialized va_list 's.vafield' is leaked}}
+} // expected-warning{{Initialized va_list 's.vafield' is leaked}}
+ // expected-note@-1{{Initialized va_list 's.vafield' is leaked}}
void casting(int fst, ...) {
char mem[sizeof(va_list)];
va_start(*(va_list *) mem, fst); // expected-note{{Initialized va_list}}
-} // expected-warning{{Initialized va_list 'mem[0]' is leaked}} expected-note{{Initialized va_list 'mem[0]' is leaked}}
+} // expected-warning{{Initialized va_list 'mem[0]' is leaked}}
+ // expected-note@-1{{Initialized va_list 'mem[0]' is leaked}}
void castingOk(int fst, ...) {
diff --git a/test/Analysis/variadic-method-types.m b/test/Analysis/variadic-method-types.m
index 9f90e5ff343d..6db93ac032e6 100644
--- a/test/Analysis/variadic-method-types.m
+++ b/test/Analysis/variadic-method-types.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.VariadicMethodTypes -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.cocoa.VariadicMethodTypes -analyzer-store=region -fblocks -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/vfork.c b/test/Analysis/vfork.c
index c7a02fa65c44..da1b5da40665 100644
--- a/test/Analysis/vfork.c
+++ b/test/Analysis/vfork.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,security.insecureAPI.vfork,unix.Vfork -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,security.insecureAPI.vfork,unix.Vfork -verify -x c++ %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,security.insecureAPI.vfork,unix.Vfork -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,security.insecureAPI.vfork,unix.Vfork -verify -x c++ %s
#include "Inputs/system-header-simulator.h"
diff --git a/test/Analysis/virtualcall.cpp b/test/Analysis/virtualcall.cpp
index 311f0a137c6f..56bd32446ee7 100644
--- a/test/Analysis/virtualcall.cpp
+++ b/test/Analysis/virtualcall.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -verify -std=c++11 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:Interprocedural=true -DINTERPROCEDURAL=1 -verify -std=c++11 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -verify -std=c++11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -verify -std=c++11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:Interprocedural=true -DINTERPROCEDURAL=1 -verify -std=c++11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -verify -std=c++11 %s
/* When INTERPROCEDURAL is set, we expect diagnostics in all functions reachable
from a constructor or destructor. If it is not set, we expect diagnostics
diff --git a/test/Analysis/vla.c b/test/Analysis/vla.c
index f94bea96e8f6..eb06c24246a7 100644
--- a/test/Analysis/vla.c
+++ b/test/Analysis/vla.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
// Zero-sized VLAs.
void check_zero_sized_VLA(int x) {
diff --git a/test/Analysis/weak-functions.c b/test/Analysis/weak-functions.c
index a983f92f81aa..514a94388722 100644
--- a/test/Analysis/weak-functions.c
+++ b/test/Analysis/weak-functions.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection,unix.Malloc,unix.cstring,alpha.unix.cstring,unix.API,osx.API,osx.cocoa.RetainCount -Wno-null-dereference -Wno-tautological-compare -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection,unix.Malloc,unix.cstring,alpha.unix.cstring,unix.API,osx.API,osx.cocoa.RetainCount -Wno-null-dereference -Wno-tautological-compare -analyzer-store=region -fblocks -verify %s
#define NULL 0
void clang_analyzer_eval(int);
void myFunc();
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 46bf2ae213ae..23d23bcddcc1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -18,6 +18,13 @@ if(CLANG_BUILT_STANDALONE)
endif()
endif()
+llvm_canonicalize_cmake_booleans(
+ CLANG_BUILD_EXAMPLES
+ CLANG_ENABLE_ARCMT
+ CLANG_ENABLE_STATIC_ANALYZER
+ ENABLE_BACKTRACES
+ HAVE_LIBZ)
+
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
@@ -55,7 +62,7 @@ if (CLANG_ENABLE_ARCMT)
)
endif ()
-if (ENABLE_CLANG_EXAMPLES)
+if (CLANG_BUILD_EXAMPLES)
list(APPEND CLANG_TEST_DEPS
AnnotateFunctions
clang-interpreter
@@ -63,7 +70,7 @@ if (ENABLE_CLANG_EXAMPLES)
)
endif ()
-if (ENABLE_CLANG_STATIC_ANALYZER AND ENABLE_CLANG_EXAMPLES)
+if (CLANG_ENABLE_STATIC_ANALYZER AND CLANG_BUILD_EXAMPLES)
list(APPEND CLANG_TEST_DEPS
SampleAnalyzerPlugin
)
@@ -79,6 +86,9 @@ if( NOT CLANG_BUILT_STANDALONE )
FileCheck count not
llc
llvm-bcanalyzer
+ llvm-cat
+ llvm-dis
+ llvm-modextract
llvm-nm
llvm-objdump
llvm-profdata
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
index f32b23976547..18b18834bb48 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
@@ -1,17 +1,25 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct X0 {
+ X0();
+ X0(int);
X0 f1();
X0 f2();
+ typedef int A;
+ typedef X0 B;
};
template<typename T>
-struct X1 {
+struct X1 : X0 {
+ X1();
X1<T>(int);
(X1<T>)(float);
X1 f2();
X1 f2(int);
X1 f2(float);
+ X1 f2(double);
+ X1 f2(short);
+ X1 f2(long);
};
// Error recovery: out-of-line constructors whose names have template arguments.
@@ -19,13 +27,88 @@ template<typename T> X1<T>::X1<T>(int) { } // expected-error{{out-of-line constr
template<typename T> (X1<T>::X1<T>)(float) { } // expected-error{{out-of-line constructor for 'X1' cannot have template arguments}}
// Error recovery: out-of-line constructor names intended to be types
-X0::X0 X0::f1() { return X0(); } // expected-error{{qualified reference to 'X0' is a constructor name rather than a type wherever a constructor can be declared}}
+X0::X0 X0::f1() { return X0(); } // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
struct X0::X0 X0::f2() { return X0(); }
-template<typename T> X1<T>::X1<T> X1<T>::f2() { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
-template<typename T> X1<T>::X1<T> (X1<T>::f2)(int) { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
+template<typename T> X1<T>::X1<T> X1<T>::f2() { } // expected-error{{missing 'typename'}}
+template<typename T> X1<T>::X1<T> (X1<T>::f2)(int) { } // expected-error{{missing 'typename'}}
template<typename T> struct X1<T>::X1<T> (X1<T>::f2)(float) { }
+template<typename T> struct X1<T>::X1 (X1<T>::f2)(double) { }
+template<typename T> typename X1<T>::template X1<T> X1<T>::f2(short) { } // expected-warning {{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
+template<typename T> typename X1<T>::template X1<T> (X1<T>::f2)(long) { } // expected-warning {{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
+
+void x1test(X1<int> x1i) {
+ x1i.f2();
+ x1i.f2(0);
+ x1i.f2(0.f);
+ x1i.f2(0.);
+}
+
+void other_contexts() {
+ X0::X0 x0; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+ X1<int>::X1 x1a; // expected-error{{qualified reference to 'X1' is a constructor name rather than a type in this context}}
+ X1<int>::X1<float> x1b; // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
+
+ X0::B ok1;
+ X0::X0::A ok2;
+ X0::X0::X0 x0b; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+ X1<int>::X0 ok3;
+ X1<int>::X0::X0 x0c; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+ X1<int>::X1<float>::X0 ok4;
+
+ {
+ typename X0::X0 tn1; // expected-warning{{qualified reference to 'X0' is a constructor name rather than a type in this context}} expected-warning 0-1{{typename}}
+ typename X1<int>::X1<float> tn2; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a template name in this context}} expected-warning 0-1{{typename}}
+ typename X0::B ok1; // expected-warning 0-1{{typename}}
+ typename X1<int>::X0 ok2; // expected-warning 0-1{{typename}}
+ }
+
+ {
+ struct X0::X0 tag1;
+ struct X1<int>::X1 tag2;
+ struct X1<int>::X1<int> tag3;
+ }
+
+ int a;
+ {
+ X0::X0(a); // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+ }
+}
+
+template<typename T> void in_instantiation_x0() {
+ typename T::X0 x0; // expected-warning{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+ typename T::A a;
+ typename T::B b;
+}
+template void in_instantiation_x0<X0>(); // expected-note {{instantiation of}}
+
+template<typename T> void in_instantiation_x1() {
+ typename T::X1 x1; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a type in this context}}
+ typename T::template X1<int> x1i; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
+ typename T::X0 x0;
+}
+template void in_instantiation_x1<X1<int> >(); // expected-note {{instantiation of}}
+
+namespace sfinae {
+ template<typename T> void f(typename T::X0 *) = delete; // expected-warning 0-1{{extension}}
+ template<typename T> void f(...);
+ void g() { f<X0>(0); }
+}
+
+namespace versus_injected_class_name {
+ template <typename T> struct A : T::B {
+ struct T::B *p;
+ typename T::B::type a;
+ A() : T::B() {}
+
+ typename T::B b; // expected-warning {{qualified reference to 'B' is a constructor name rather than a type in this context}}
+ };
+ struct B {
+ typedef int type;
+ };
+ template struct A<B>; // expected-note {{in instantiation of}}
+}
// We have a special case for lookup within using-declarations that are
// member-declarations: foo::bar::baz::baz always names baz's constructor
@@ -109,7 +192,7 @@ namespace InhCtor {
// FIXME: Consider reusing the same diagnostic between dependent and non-dependent contexts
typedef int I;
struct UsingInt {
- using I::I; // expected-error {{'I' (aka 'int') is not a class, namespace, or enumeration}}
+ using I::I; // expected-error {{'InhCtor::I' (aka 'int') is not a class, namespace, or enumeration}}
};
template<typename T> struct UsingIntTemplate {
using T::T; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
diff --git a/test/CXX/class.derived/class.abstract/p16.cpp b/test/CXX/class.derived/class.abstract/p16.cpp
index 29adbccac479..80396a96d9ec 100644
--- a/test/CXX/class.derived/class.abstract/p16.cpp
+++ b/test/CXX/class.derived/class.abstract/p16.cpp
@@ -35,13 +35,15 @@ struct E : D {};
// expected-error@-1 {{deleted function '~E' cannot override a non-deleted function}}
// expected-note@-2 {{destructor of 'E' is implicitly deleted because base class 'D' has an inaccessible destructor}}
// expected-error@-3 {{deleted function 'operator=' cannot override a non-deleted function}}
-// expected-note@-4 {{copy assignment operator of 'E' is implicitly deleted because base class 'D' has an inaccessible copy assignment operator}}
+// expected-note@-4 {{while declaring the implicit copy assignment operator for 'E'}}
+// expected-note@-5 {{copy assignment operator of 'E' is implicitly deleted because base class 'D' has an inaccessible copy assignment operator}}
struct F : D {};
struct G : D {};
// expected-error@-1 {{deleted function '~G' cannot override a non-deleted function}}
-// expected-note@-2 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
+// expected-note@-2 {{destructor of 'G' is implicitly deleted because base class 'D' has an inaccessible destructor}}
// expected-error@-3 {{deleted function 'operator=' cannot override a non-deleted function}}
-// expected-note@-4 {{destructor of 'G' is implicitly deleted because base class 'D' has an inaccessible destructor}}
+// expected-note@-4 {{while declaring the implicit move assignment operator for 'G'}}
+// expected-note@-5 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
struct H : D {
H &operator=(H&&) = default;
// expected-error@-1 {{deleted function 'operator=' cannot override a non-deleted function}}
diff --git a/test/CXX/class.derived/class.member.lookup/p10.cpp b/test/CXX/class.derived/class.member.lookup/p10.cpp
new file mode 100644
index 000000000000..afd87521885a
--- /dev/null
+++ b/test/CXX/class.derived/class.member.lookup/p10.cpp
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wshadow-all
+
+// Basic cases, ambiguous paths, and fields with different access
+class A {
+public:
+ int x; // expected-note 2{{declared here}}
+protected:
+ int y; // expected-note 2{{declared here}}
+private:
+ int z;
+};
+
+struct B : A {
+};
+
+struct C : A {
+};
+
+struct W {
+ int w; // expected-note {{declared here}}
+};
+
+struct U : W {
+};
+
+struct V : W {
+};
+
+class D {
+public:
+ char w; // expected-note {{declared here}}
+private:
+ char x;
+};
+
+// Check direct inheritance and multiple paths to the same base.
+class E : B, C, D, U, V
+{
+ unsigned x; // expected-warning {{non-static data member 'x' of 'E' shadows member inherited from type 'A'}}
+ char y; // expected-warning {{non-static data member 'y' of 'E' shadows member inherited from type 'A'}}
+ double z;
+ char w; // expected-warning {{non-static data member 'w' of 'E' shadows member inherited from type 'D'}} expected-warning {{non-static data member 'w' of 'E' shadows member inherited from type 'W'}}
+};
+
+// Virtual inheritance
+struct F : virtual A {
+};
+
+struct G : virtual A {
+};
+
+class H : F, G {
+ int x; // expected-warning {{non-static data member 'x' of 'H' shadows member inherited from type 'A'}}
+ int y; // expected-warning {{non-static data member 'y' of 'H' shadows member inherited from type 'A'}}
+ int z;
+};
+
+// Indirect inheritance
+struct I {
+ union {
+ int x; // expected-note {{declared here}}
+ int y;
+ };
+};
+
+struct J : I {
+ int x; // expected-warning {{non-static data member 'x' of 'J' shadows member inherited from type 'I'}}
+};
+
+// non-access paths
+class N : W {
+};
+
+struct K {
+ int y;
+};
+
+struct L : private K {
+};
+
+struct M : L {
+ int y;
+ int w;
+};
+
+// Multiple ambiguous paths with different accesses
+struct A1 {
+ int x; // expected-note {{declared here}}
+};
+
+class B1 : A1 {
+};
+
+struct B2 : A1 {
+};
+
+struct C1 : B1, B2 {
+};
+
+class D1 : C1 {
+};
+
+struct D2 : C1 {
+};
+
+class D3 : C1 {
+};
+
+struct E1 : D1, D2, D3{
+ int x; // expected-warning {{non-static data member 'x' of 'E1' shadows member inherited from type 'A1'}}
+};
+
+
+
diff --git a/test/CXX/class.derived/class.member.lookup/p6.cpp b/test/CXX/class.derived/class.member.lookup/p6.cpp
index 72398819263f..0a400a2405e9 100644
--- a/test/CXX/class.derived/class.member.lookup/p6.cpp
+++ b/test/CXX/class.derived/class.member.lookup/p6.cpp
@@ -1,24 +1,24 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wshadow-field
class V {
public:
int f();
- int x;
+ int x; // expected-note {{declared here}}
};
class W {
public:
int g(); // expected-note{{member found by ambiguous name lookup}}
- int y; // expected-note{{member found by ambiguous name lookup}}
+ int y; // expected-note{{member found by ambiguous name lookup}} expected-note {{declared here}}
};
class B : public virtual V, public W
{
public:
int f();
- int x;
+ int x; // expected-warning {{non-static data member 'x' of 'B' shadows member inherited from type 'V'}}
int g(); // expected-note{{member found by ambiguous name lookup}}
- int y; // expected-note{{member found by ambiguous name lookup}}
+ int y; // expected-note{{member found by ambiguous name lookup}} expected-warning {{non-static data member 'y' of 'B' shadows member inherited from type 'W'}}
};
class C : public virtual V, public W { };
diff --git a/test/CXX/class.derived/class.member.lookup/p7.cpp b/test/CXX/class.derived/class.member.lookup/p7.cpp
index a785e0f90e57..775057792c5c 100644
--- a/test/CXX/class.derived/class.member.lookup/p7.cpp
+++ b/test/CXX/class.derived/class.member.lookup/p7.cpp
@@ -1,11 +1,9 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify %s -Wshadow-field
-// expected-no-diagnostics
-
-struct A { int n; };
-struct B { float n; };
+struct A { int n; }; // expected-note {{declared here}}
+struct B { float n; }; // expected-note {{declared here}}
struct C : A, B {};
struct D : virtual C {};
-struct E : virtual C { char n; };
+struct E : virtual C { char n; }; // expected-warning {{non-static data member 'n' of 'E' shadows member inherited from type 'A'}} expected-warning {{non-static data member 'n' of 'E' shadows member inherited from type 'B'}}
struct F : D, E {} f;
char &k = f.n;
diff --git a/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp b/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
new file mode 100644
index 000000000000..d1ad0404ef42
--- /dev/null
+++ b/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
+
+namespace nodiag {
+
+template <typename T> requires bool(T())
+struct A;
+template <typename U> requires bool(U())
+struct A;
+
+} // end namespace nodiag
+
+namespace diag {
+
+template <typename T> requires true // expected-note{{previous template declaration is here}}
+struct A;
+template <typename T> struct A; // expected-error{{associated constraints differ in template redeclaration}}
+
+template <typename T> struct B; // expected-note{{previous template declaration is here}}
+template <typename T> requires true // expected-error{{associated constraints differ in template redeclaration}}
+struct B;
+
+template <typename T> requires true // expected-note{{previous template declaration is here}}
+struct C;
+template <typename T> requires !0 // expected-error{{associated constraints differ in template redeclaration}}
+struct C;
+
+} // end namespace diag
+
+namespace nodiag {
+
+struct AA {
+ template <typename T> requires someFunc(T())
+ struct A;
+};
+
+template <typename T> requires someFunc(T())
+struct AA::A { };
+
+struct AAF {
+ template <typename T> requires someFunc(T())
+ friend struct AA::A;
+};
+
+} // end namespace nodiag
+
+namespace diag {
+
+template <unsigned N>
+struct TA {
+ template <template <unsigned> class TT> requires TT<N>::happy // expected-note 2{{previous template declaration is here}}
+ struct A;
+
+ struct AF;
+};
+
+template <unsigned N>
+template <template <unsigned> class TT> struct TA<N>::A { }; // expected-error{{associated constraints differ in template redeclaration}}
+
+template <unsigned N>
+struct TA<N>::AF {
+ template <template <unsigned> class TT> requires TT<N + 0>::happy // expected-error{{associated constraints differ in template redeclaration}}
+ friend struct TA::A;
+};
+
+} // end namespace diag
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
index a27cea84db45..58c7c0cfac8b 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
@@ -23,7 +23,38 @@ template <> class [[deprecated]] X<int> {}; // expected-note {{'X<int>' has been
X<char> x1;
X<int> x2; // expected-warning {{'X<int>' is deprecated}}
-template <typename T> class [[deprecated]] X2 {};
+template <typename T> class [[deprecated]] X2 {}; //expected-note {{'X2<char>' has been explicitly marked deprecated here}}
template <> class X2<int> {};
-X2<char> x3; // FIXME: no warning!
-X2<int> x4;
+X2<char> x3; // expected-warning {{'X2<char>' is deprecated}}
+X2<int> x4; // No warning, the specialization removes it.
+
+template <typename T> class [[deprecated]] X3; //expected-note {{'X3<char>' has been explicitly marked deprecated here}}
+template <> class X3<int>;
+X3<char> *x5; // expected-warning {{'X3<char>' is deprecated}}
+X3<int> *x6; // No warning, the specialization removes it.
+
+template <typename T> struct A;
+A<int> *p;
+template <typename T> struct [[deprecated]] A;//expected-note {{'A<int>' has been explicitly marked deprecated here}} expected-note {{'A<float>' has been explicitly marked deprecated here}}
+A<int> *q; // expected-warning {{'A<int>' is deprecated}}
+A<float> *r; // expected-warning {{'A<float>' is deprecated}}
+
+template <typename T> struct B;
+B<int> *p2;
+template <typename T> struct [[deprecated]] B;//expected-note {{'B<int>' has been explicitly marked deprecated here}} expected-note {{'B<float>' has been explicitly marked deprecated here}}
+B<int> *q2; // expected-warning {{'B<int>' is deprecated}}
+B<float> *r2; // expected-warning {{'B<float>' is deprecated}}
+
+template <typename T>
+T some_func(T t) {
+ struct [[deprecated]] FunS{}; // expected-note {{'FunS' has been explicitly marked deprecated here}}
+ FunS f;// expected-warning {{'FunS' is deprecated}}
+
+}
+
+template <typename T>
+[[deprecated]]T some_func2(T t) {
+ struct FunS2{};
+ FunS2 f;// No warning, entire function is deprecated, so usage here should be fine.
+
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
index eb751517e2f2..e8f12156a424 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
@@ -3,15 +3,15 @@
// FIXME: This is in p11 (?) in C++1y.
void f() {
- decltype(auto) a = a; // expected-error{{variable 'a' declared with 'decltype(auto)' type cannot appear in its own initializer}}
- if (decltype(auto) b = b) {} // expected-error {{variable 'b' declared with 'decltype(auto)' type cannot appear in its own initializer}}
- decltype(auto) c = ({ decltype(auto) d = c; 0; }); // expected-error {{variable 'c' declared with 'decltype(auto)' type cannot appear in its own initializer}}
+ decltype(auto) a = a; // expected-error{{variable 'a' declared with deduced type 'decltype(auto)' cannot appear in its own initializer}}
+ if (decltype(auto) b = b) {} // expected-error {{variable 'b' declared with deduced type 'decltype(auto)' cannot appear in its own initializer}}
+ decltype(auto) c = ({ decltype(auto) d = c; 0; }); // expected-error {{variable 'c' declared with deduced type 'decltype(auto)' cannot appear in its own initializer}}
}
void g() {
- decltype(auto) a; // expected-error{{declaration of variable 'a' with type 'decltype(auto)' requires an initializer}}
+ decltype(auto) a; // expected-error{{declaration of variable 'a' with deduced type 'decltype(auto)' requires an initializer}}
- decltype(auto) *b; // expected-error{{cannot form pointer to 'decltype(auto)'}} expected-error{{declaration of variable 'b' with type 'decltype(auto) *' requires an initializer}}
+ decltype(auto) *b; // expected-error{{cannot form pointer to 'decltype(auto)'}} expected-error{{declaration of variable 'b' with deduced type 'decltype(auto) *' requires an initializer}}
if (decltype(auto) b) {} // expected-error {{must have an initializer}}
for (;decltype(auto) b;) {} // expected-error {{must have an initializer}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1z.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1z.cpp
new file mode 100644
index 000000000000..73caa2de044e
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1z.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z
+
+// FIXME: This is in p10 (?) in C++1z.
+template<typename T> struct A {
+ A(T);
+};
+template<typename T> A(T) -> A<T>;
+A a = a; // expected-error{{variable 'a' declared with deduced type 'A' cannot appear in its own initializer}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
index e91cacf10466..440c78201293 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
@@ -1,17 +1,17 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions -Wc++11-compat
void f() {
- auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}}
- auto *b = b; // expected-error{{variable 'b' declared with 'auto' type cannot appear in its own initializer}}
- const auto c = c; // expected-error{{variable 'c' declared with 'auto' type cannot appear in its own initializer}}
- if (auto d = d) {} // expected-error {{variable 'd' declared with 'auto' type cannot appear in its own initializer}}
- auto e = ({ auto f = e; 0; }); // expected-error {{variable 'e' declared with 'auto' type cannot appear in its own initializer}}
+ auto a = a; // expected-error{{variable 'a' declared with deduced type 'auto' cannot appear in its own initializer}}
+ auto *b = b; // expected-error{{variable 'b' declared with deduced type 'auto *' cannot appear in its own initializer}}
+ const auto c = c; // expected-error{{variable 'c' declared with deduced type 'const auto' cannot appear in its own initializer}}
+ if (auto d = d) {} // expected-error {{variable 'd' declared with deduced type 'auto' cannot appear in its own initializer}}
+ auto e = ({ auto f = e; 0; }); // expected-error {{variable 'e' declared with deduced type 'auto' cannot appear in its own initializer}}
}
void g() {
- auto a; // expected-error{{declaration of variable 'a' with type 'auto' requires an initializer}}
+ auto a; // expected-error{{declaration of variable 'a' with deduced type 'auto' requires an initializer}}
- auto *b; // expected-error{{declaration of variable 'b' with type 'auto *' requires an initializer}}
+ auto *b; // expected-error{{declaration of variable 'b' with deduced type 'auto *' requires an initializer}}
if (auto b) {} // expected-error {{must have an initializer}}
for (;auto b;) {} // expected-error {{must have an initializer}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
index 46c874f605cb..bf1b3092e08e 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
@@ -36,7 +36,7 @@ class X {
};
struct S {
- static const auto a; // expected-error {{declaration of variable 'a' with type 'const auto' requires an initializer}}
+ static const auto a; // expected-error {{declaration of variable 'a' with deduced type 'const auto' requires an initializer}}
static const auto b = 0;
static const int c;
};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
index 0cdf3c6e053f..a260f99f5cf1 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -9,7 +9,7 @@ struct S {
void f() throw (auto); // expected-error{{'auto' not allowed here}}
- friend auto; // expected-error{{'auto' not allowed in non-static struct member}}
+ friend auto; // expected-error{{'auto' not allowed in friend declaration}}
operator auto(); // expected-error{{'auto' not allowed in conversion function type}}
};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
index 06bd72e125d1..60ddabeb4a90 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
@@ -51,7 +51,7 @@ decltype(auto) *f3(); // expected-error {{cannot form pointer to 'decltype(auto)
const decltype(auto) f4(); // expected-error {{'decltype(auto)' cannot be combined with other type specifiers}}
typedef decltype(auto) f5(); // expected-error {{'decltype(auto)' not allowed in typedef}}
decltype(auto) ((((((f6))))())); // ok
-decltype(auto) f7()(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{function cannot return function type}}
+decltype(auto) f7()(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}}
decltype(auto) (S::*f8)(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{requires an initializer}}
decltype(auto) &f9(); // expected-error {{cannot form reference to 'decltype(auto)'}}
decltype(auto) (&f10())[10]; // expected-error {{cannot form array of 'decltype(auto)'}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
index 8d789bdd5ad3..e9294d7f4362 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions
void f() {
@@ -19,22 +20,42 @@ void f() {
}
void g() {
- auto a = 0,
#if __has_feature(cxx_trailing_return)
- (*b)() -> void,
-#endif
+ auto a = 0,
+ (*b)() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
c = 0;
- auto d = 0, // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}}
-#if __has_feature(cxx_trailing_return)
- (*e)() -> void,
-#endif
+ auto d = 0,
+ e() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
f = 0.0;
+ auto x() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+ y() -> void;
+#endif
#if __has_feature(cxx_decltype)
auto g = 0ull, h = decltype(g)(0);
#endif
}
+#if __has_feature(cxx_trailing_return)
+int F();
+auto p = 0, (*q)() -> auto = F; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+ #if __cplusplus < 201402L
+ // expected-error@-2 {{'auto' not allowed in function return type}}
+ #endif
+#endif
+
+#if __cplusplus >= 201402L
+namespace DeducedReturnType {
+ auto a = 0,
+ b(), // expected-error {{function with deduced return type must be the only declaration in its group}}
+ c = 0.0;
+ auto d(), // expected-error {{function with deduced return type must be the only declaration in its group}}
+ e = 1;
+ auto f(), // expected-error {{function with deduced return type must be the only declaration in its group}}
+ g();
+}
+#endif
+
template<typename T> void h() {
auto a = T(), *b = &a;
#if __has_feature(cxx_decltype)
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp
new file mode 100644
index 000000000000..cfb9a61f1ac4
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+template<typename T> struct A { constexpr A(int = 0) {} };
+A() -> A<int>;
+A(int) -> A<char>;
+
+static constexpr inline const volatile A a = {}; // ok, specifiers are permitted
+// FIXME: There isn't really a good reason to reject this.
+A b; // expected-error {{requires an initializer}}
+A c [[]] {};
+
+A d = {}, e = {};
+A f(0), g{}; // expected-error {{template arguments deduced as 'A<char>' in declaration of 'f' and deduced as 'A<int>' in declaration of 'g'}}
+
+struct B {
+ static A a; // expected-error {{requires an initializer}}
+};
+extern A x; // expected-error {{requires an initializer}}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp
index f381ed708f70..ade327485773 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp
@@ -150,35 +150,44 @@ namespace cxx1z_direct_enum_init {
void f(T);
f(T{0});
+
+ char c;
+ auto t3 = T{c};
}
#if __cplusplus <= 201402L
- // expected-error@-15 5{{cannot initialize}}
- // expected-error@-15 5{{cannot initialize}}
- // expected-error@-15 5{{cannot initialize}}
+ // expected-error@-18 5{{cannot initialize}}
+ // expected-error@-18 5{{cannot initialize}}
+ // expected-error@-18 5{{cannot initialize}}
+ //
//
+ // expected-error@-18 5{{cannot initialize}}
//
- // expected-error@-15 5{{cannot initialize}}
+ // expected-error@-18 5{{cannot initialize}}
//
- // expected-error@-15 5{{cannot initialize}}
+ // expected-error@-18 5{{cannot initialize}}
//
- // expected-error@-15 5{{cannot initialize}}
//
+ // expected-error@-18 5{{cannot initialize}}
//
- // expected-error@-15 5{{cannot initialize}}
+ //
+ // expected-error@-18 5{{cannot initialize}}
#else
- // expected-error@-29 {{cannot initialize}}
- // expected-error@-29 {{cannot initialize}}
- // expected-error@-29 {{cannot initialize}}
+ // expected-error@-35 {{cannot initialize}}
+ // expected-error@-35 {{cannot initialize}}
+ // expected-error@-35 {{cannot initialize}}
+ //
//
+ // expected-error@-35 {{cannot initialize}}
//
- // expected-error@-29 {{cannot initialize}}
+ // expected-error@-35 {{cannot initialize}}
//
- // expected-error@-29 {{cannot initialize}}
+ // expected-error@-35 {{cannot initialize}}
//
- // expected-error@-29 {{cannot initialize}}
//
+ // expected-error@-35 {{cannot initialize}}
//
- // expected-error@-29 {{cannot initialize}}
+ //
+ // expected-error@-35 {{cannot initialize}}
#endif
template<typename T> void bad() {
@@ -252,4 +261,12 @@ namespace cxx1z_direct_enum_init {
(void)B{0.0}; // expected-error {{type 'double' cannot be narrowed}}
#endif
}
+
+#if __cplusplus > 201402L
+ enum class F : unsigned {};
+ F f1(unsigned x) { return F{x}; }
+ F f2(const unsigned x) { return F{x}; }
+ F f3(bool x) { return F{x}; }
+ F f4(const bool x) { return F{x}; }
+#endif
}
diff --git a/test/CXX/drs/dr10xx.cpp b/test/CXX/drs/dr10xx.cpp
index e11e796165e2..e1db9ef54adf 100644
--- a/test/CXX/drs/dr10xx.cpp
+++ b/test/CXX/drs/dr10xx.cpp
@@ -12,6 +12,30 @@ namespace std {
};
}
+namespace dr1004 { // dr1004: 5
+ template<typename> struct A {};
+ template<typename> struct B1 {};
+ template<template<typename> class> struct B2 {};
+ template<typename X> void f(); // expected-note {{[with X = dr1004::A<int>]}}
+ template<template<typename> class X> void f(); // expected-note {{[with X = A]}}
+ template<template<typename> class X> void g(); // expected-note {{[with X = A]}}
+ template<typename X> void g(); // expected-note {{[with X = dr1004::A<int>]}}
+ struct C : A<int> {
+ B1<A> b1a;
+ B2<A> b2a;
+ void h() {
+ f<A>(); // expected-error {{ambiguous}}
+ g<A>(); // expected-error {{ambiguous}}
+ }
+ };
+
+ // This example (from the standard) is actually ill-formed, because
+ // name lookup of "T::template A" names the constructor.
+ // FIXME: Only issue one diagnostic for this case.
+ template<class T, template<class> class U = T::template A> struct Third { }; // expected-error 2{{is a constructor name}}
+ Third<A<int> > t; // expected-note {{in instantiation of}} expected-note {{while substituting}} expected-note {{while checking}}
+}
+
namespace dr1048 { // dr1048: 3.6
struct A {};
const A f();
diff --git a/test/CXX/drs/dr12xx.cpp b/test/CXX/drs/dr12xx.cpp
index 45b33f9d7daf..24039a1cd240 100644
--- a/test/CXX/drs/dr12xx.cpp
+++ b/test/CXX/drs/dr12xx.cpp
@@ -14,7 +14,7 @@ namespace dr1213 { // dr1213: 4
#endif
}
-namespace dr1250 { // dr1250: 3.9
+namespace dr1250 { // dr1250: 3.9
struct Incomplete;
struct Base {
@@ -24,9 +24,23 @@ struct Base {
struct Derived : Base {
virtual Incomplete *meow();
};
-} // dr1250
+}
+
+namespace dr1265 { // dr1265: 5
+#if __cplusplus >= 201103L
+ auto a = 0, b() -> int; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+ auto b() -> int, d = 0; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+ auto e() -> int, f() -> int; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+#endif
+
+#if __cplusplus >= 201402L
+ auto g(), h = 0; // expected-error {{function with deduced return type must be the only declaration in its group}}
+ auto i = 0, j(); // expected-error {{function with deduced return type must be the only declaration in its group}}
+ auto k(), l(); // expected-error {{function with deduced return type must be the only declaration in its group}}
+#endif
+}
-namespace dr1295 { // dr1295: 4
+namespace dr1295 { // dr1295: 4
struct X {
unsigned bitfield : 4;
};
diff --git a/test/CXX/drs/dr13xx.cpp b/test/CXX/drs/dr13xx.cpp
index f35ead7b5e94..56ff1237480f 100644
--- a/test/CXX/drs/dr13xx.cpp
+++ b/test/CXX/drs/dr13xx.cpp
@@ -3,6 +3,96 @@
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+__extension__ typedef __SIZE_TYPE__ size_t;
+
+namespace std {
+ template<typename T> struct initializer_list {
+ const T *ptr;
+ size_t n;
+ initializer_list(const T*, size_t);
+ };
+}
+
+namespace dr1310 { // dr1310: 5
+ struct S {} * sp = new S::S; // expected-error {{qualified reference to 'S' is a constructor name}}
+ void f() {
+ S::S(a); // expected-error {{qualified reference to 'S' is a constructor name}}
+ }
+ struct T { int n; typedef int U; typedef T V; };
+ int k = T().T::T::n;
+ T::V v;
+
+ struct U { int U; };
+ int u = U().U::U;
+ struct U::U w;
+
+ struct V : T::T {
+ // FIXME: This is technically ill-formed, but we consider that to be a defect.
+ V() : T::T() {}
+ };
+ template<typename T> struct VT : T::T {
+ VT() : T::T() {}
+ };
+ template struct VT<T>;
+
+ template<template<typename> class> class TT {};
+ template<typename> class TTy {};
+
+ template<typename T> struct WBase {};
+ template<typename T> struct W : WBase<T> { typedef int X; int n; };
+
+ void w_test() {
+ W<int>::W w1a; // expected-error {{qualified reference to 'W' is a constructor name}}
+ W<int>::W::X w1ax;
+ W<int>::W<int> w1b; // expected-error {{qualified reference to 'W' is a constructor name}}
+ W<int>::W<int>::X w1bx;
+ typename W<int>::W w2a; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{outside of a template}}
+ typename W<int>::W::X w2ax; // expected-error 0-1{{outside of a template}}
+ typename W<int>::W<int> w2b; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{outside of a template}}
+ typename W<int>::W<int>::X w2bx; // expected-error 0-1{{outside of a template}}
+ W<int>::template W<int> w3; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{outside of a template}}
+ W<int>::template W<int>::X w3x; // expected-error 0-1{{outside of a template}}
+ typename W<int>::template W<int> w4; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-2{{outside of a template}}
+ typename W<int>::template W<int>::X w4x; // expected-error 0-2{{outside of a template}}
+
+ TT<W<int>::W> tt1; // expected-error {{qualified reference to 'W' is a constructor name}}
+ TTy<W<int>::W> tt1a; // expected-error {{qualified reference to 'W' is a constructor name}}
+ TT<W<int>::template W> tt2; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{outside of a template}}
+ TT<W<int>::WBase> tt3;
+ TTy<W<int>::WBase> tt3a;
+ TT<W<int>::template WBase> tt4; // expected-error 0-1{{outside of a template}}
+
+ W<int> w;
+ (void)w.W::W::n;
+ (void)w.W<int>::W::n;
+ (void)w.W<int>::W<int>::n;
+ (void)w.W<int>::template W<int>::n; // expected-error 0-1{{outside of a template}}
+ }
+
+ template<typename W>
+ void wt_test() {
+ typename W::W w2a; // expected-error {{qualified reference to 'W' is a constructor name}}
+ typename W::template W<int> w4; // expected-error {{qualified reference to 'W' is a constructor name}}
+ TTy<typename W::W> tt2; // expected-error {{qualified reference to 'W' is a constructor name}}
+ TT<W::template W> tt3; // expected-error {{qualified reference to 'W' is a constructor name}}
+ }
+ template<typename W>
+ void wt_test_good() {
+ typename W::W::X w2ax;
+ typename W::template W<int>::X w4x;
+ TTy<typename W::WBase> tt4;
+ TT<W::template WBase> tt5;
+
+ W w;
+ (void)w.W::W::n;
+ (void)w.W::template W<int>::n;
+ (void)w.template W<int>::W::n;
+ (void)w.template W<int>::template W<int>::n;
+ }
+ template void wt_test<W<int> >(); // expected-note {{instantiation of}}
+ template void wt_test_good<W<int> >();
+}
+
namespace dr1315 { // dr1315: partial
template <int I, int J> struct A {};
template <int I> // expected-note {{non-deducible template parameter 'I'}}
@@ -159,6 +249,15 @@ namespace dr1346 { // dr1346: 3.5
#endif
}
+namespace dr1347 { // dr1347: yes
+ auto x = 5, *y = &x; // expected-error 0-1{{extension}}
+ auto z = y, *q = y; // expected-error {{'auto' deduced as 'int *' in declaration of 'z' and deduced as 'int' in declaration of 'q'}} expected-error 0-1{{extension}}
+#if __cplusplus >= 201103L
+ auto a = 5, b = {1, 2}; // expected-error {{'auto' deduced as 'int' in declaration of 'a' and deduced as 'std::initializer_list<int>' in declaration of 'b'}}
+ auto (*fp)(int) -> int, i = 0; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
+#endif
+}
+
namespace dr1359 { // dr1359: 3.5
#if __cplusplus >= 201103L
union A { constexpr A() = default; };
diff --git a/test/CXX/drs/dr16xx.cpp b/test/CXX/drs/dr16xx.cpp
index c9f084db73a1..08ae92570cec 100644
--- a/test/CXX/drs/dr16xx.cpp
+++ b/test/CXX/drs/dr16xx.cpp
@@ -3,6 +3,13 @@
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+namespace dr1611 { // dr1611: dup 1658
+ struct A { A(int); };
+ struct B : virtual A { virtual void f() = 0; };
+ struct C : B { C() : A(0) {} void f(); };
+ C c;
+}
+
namespace dr1684 { // dr1684: 3.6
#if __cplusplus >= 201103L
struct NonLiteral { // expected-note {{because}}
@@ -101,3 +108,114 @@ namespace dr1653 { // dr1653: 4 c++17
b -= 1; // ok
}
}
+
+namespace dr1658 { // dr1658: 5
+ namespace DefCtor {
+ class A { A(); }; // expected-note 0-2{{here}}
+ class B { ~B(); }; // expected-note 0-2{{here}}
+
+ // The stars align! An abstract class does not construct its virtual bases.
+ struct C : virtual A { C(); virtual void foo() = 0; };
+ C::C() = default; // ok, not deleted, expected-error 0-1{{extension}}
+ struct D : virtual B { D(); virtual void foo() = 0; };
+ D::D() = default; // ok, not deleted, expected-error 0-1{{extension}}
+
+ // In all other cases, we are not so lucky.
+ struct E : A { E(); virtual void foo() = 0; };
+#if __cplusplus < 201103L
+ E::E() = default; // expected-error {{private default constructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ E::E() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible default constructor}}
+#endif
+ struct F : virtual A { F(); };
+#if __cplusplus < 201103L
+ F::F() = default; // expected-error {{private default constructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ F::F() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible default constructor}}
+#endif
+
+ struct G : B { G(); virtual void foo() = 0; };
+#if __cplusplus < 201103L
+ G::G() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ G::G() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}}
+#endif
+ struct H : virtual B { H(); };
+#if __cplusplus < 201103L
+ H::H() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ H::H() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}}
+#endif
+ }
+
+ namespace Dtor {
+ class B { ~B(); }; // expected-note 0-2{{here}}
+
+ struct D : virtual B { ~D(); virtual void foo() = 0; };
+ D::~D() = default; // ok, not deleted, expected-error 0-1{{extension}}
+
+ struct G : B { ~G(); virtual void foo() = 0; };
+#if __cplusplus < 201103L
+ G::~G() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ G::~G() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}}
+#endif
+ struct H : virtual B { ~H(); };
+#if __cplusplus < 201103L
+ H::~H() = default; // expected-error@-2 {{private destructor}} expected-error {{extension}} expected-note {{here}}
+#else
+ H::~H() = default; // expected-error {{would delete}} expected-note@-4{{inaccessible destructor}}
+#endif
+ }
+
+ namespace MemInit {
+ struct A { A(int); }; // expected-note {{here}}
+ struct B : virtual A {
+ B() {}
+ virtual void f() = 0;
+ };
+ struct C : virtual A {
+ C() {} // expected-error {{must explicitly initialize}}
+ };
+ }
+
+ namespace CopyCtorParamType {
+ struct A { A(A&); };
+ struct B : virtual A { virtual void f() = 0; };
+ struct C : virtual A { virtual void f(); };
+ struct D : A { virtual void f() = 0; };
+
+ struct X {
+ friend B::B(const B&) throw();
+ friend C::C(C&);
+ friend D::D(D&);
+ };
+ }
+
+ namespace CopyCtor {
+ class A { A(const A&); A(A&&); }; // expected-note 0-4{{here}} expected-error 0-1{{extension}}
+
+ struct C : virtual A { C(const C&); C(C&&); virtual void foo() = 0; }; // expected-error 0-1{{extension}}
+ C::C(const C&) = default; // expected-error 0-1{{extension}}
+ C::C(C&&) = default; // expected-error 0-2{{extension}}
+
+ struct E : A { E(const E&); E(E&&); virtual void foo() = 0; }; // expected-error 0-1{{extension}}
+#if __cplusplus < 201103L
+ E::E(const E&) = default; // expected-error {{private copy constructor}} expected-error {{extension}} expected-note {{here}}
+ E::E(E&&) = default; // expected-error {{private move constructor}} expected-error 2{{extension}} expected-note {{here}}
+#else
+ E::E(const E&) = default; // expected-error {{would delete}} expected-note@-5{{inaccessible copy constructor}}
+ E::E(E&&) = default; // expected-error {{would delete}} expected-note@-6{{inaccessible move constructor}}
+#endif
+ struct F : virtual A { F(const F&); F(F&&); }; // expected-error 0-1{{extension}}
+#if __cplusplus < 201103L
+ F::F(const F&) = default; // expected-error {{private copy constructor}} expected-error {{extension}} expected-note {{here}}
+ F::F(F&&) = default; // expected-error {{private move constructor}} expected-error 2{{extension}} expected-note {{here}}
+#else
+ F::F(const F&) = default; // expected-error {{would delete}} expected-note@-5{{inaccessible copy constructor}}
+ F::F(F&&) = default; // expected-error {{would delete}} expected-note@-6{{inaccessible move constructor}}
+#endif
+ }
+
+ // assignment case is superseded by dr2180
+}
diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp
index 9521f0a8b784..f5395cfe183d 100644
--- a/test/CXX/drs/dr1xx.cpp
+++ b/test/CXX/drs/dr1xx.cpp
@@ -535,13 +535,15 @@ namespace dr145 { // dr145: yes
}
}
-namespace dr147 { // dr147: no
+namespace dr147 { // dr147: yes
namespace example1 {
template<typename> struct A {
template<typename T> A(T);
};
- // FIXME: This appears to be valid, and EDG and G++ accept.
+ // Per core issue 1435, this is ill-formed because A<int>::A<int> does not
+ // name the injected-class-name. (A<int>::A does, though.)
template<> template<> A<int>::A<int>(int) {} // expected-error {{out-of-line constructor for 'A' cannot have template arguments}}
+ template<> template<> A<float>::A(float) {}
}
namespace example2 {
struct A { A(); };
diff --git a/test/CXX/drs/dr21xx.cpp b/test/CXX/drs/dr21xx.cpp
new file mode 100644
index 000000000000..78fc0bec40bf
--- /dev/null
+++ b/test/CXX/drs/dr21xx.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+namespace dr2180 { // dr2180: yes
+ class A {
+ A &operator=(const A &); // expected-note 0-2{{here}}
+ A &operator=(A &&); // expected-note 0-2{{here}} expected-error 0-1{{extension}}
+ };
+
+ struct B : virtual A {
+ B &operator=(const B &);
+ B &operator=(B &&); // expected-error 0-1{{extension}}
+ virtual void foo() = 0;
+ };
+#if __cplusplus < 201103L
+ B &B::operator=(const B&) = default; // expected-error {{private member}} expected-error {{extension}} expected-note {{here}}
+ B &B::operator=(B&&) = default; // expected-error {{private member}} expected-error 2{{extension}} expected-note {{here}}
+#else
+ B &B::operator=(const B&) = default; // expected-error {{would delete}} expected-note@-9{{inaccessible copy assignment}}
+ B &B::operator=(B&&) = default; // expected-error {{would delete}} expected-note@-10{{inaccessible move assignment}}
+#endif
+}
diff --git a/test/CXX/drs/dr2xx.cpp b/test/CXX/drs/dr2xx.cpp
index 68261f6c00f1..a5677a125a00 100644
--- a/test/CXX/drs/dr2xx.cpp
+++ b/test/CXX/drs/dr2xx.cpp
@@ -1014,7 +1014,7 @@ namespace dr294 { // dr294: no
namespace dr295 { // dr295: 3.7
typedef int f();
- const f g; // expected-warning {{'const' qualifier on function type 'f' (aka 'int ()') has no effect}}
+ const f g; // expected-warning {{'const' qualifier on function type 'dr295::f' (aka 'int ()') has no effect}}
f &r = g;
template<typename T> struct X {
const T &f;
@@ -1022,10 +1022,10 @@ namespace dr295 { // dr295: 3.7
X<f> x = {g};
typedef int U();
- typedef const U U; // expected-warning {{'const' qualifier on function type 'U' (aka 'int ()') has no effect}}
+ typedef const U U; // expected-warning {{'const' qualifier on function type 'dr295::U' (aka 'int ()') has no effect}}
typedef int (*V)();
- typedef volatile U *V; // expected-warning {{'volatile' qualifier on function type 'U' (aka 'int ()') has no effect}}
+ typedef volatile U *V; // expected-warning {{'volatile' qualifier on function type 'dr295::U' (aka 'int ()') has no effect}}
}
namespace dr296 { // dr296: yes
@@ -1053,7 +1053,7 @@ namespace dr298 { // dr298: yes
B::B() {} // expected-error {{requires a type specifier}}
B::A() {} // ok
- C::~C() {} // expected-error {{destructor cannot be declared using a typedef 'C' (aka 'const dr298::A') of the class name}}
+ C::~C() {} // expected-error {{destructor cannot be declared using a typedef 'dr298::C' (aka 'const dr298::A') of the class name}}
typedef struct D E; // expected-note {{here}}
struct E {}; // expected-error {{conflicts with typedef}}
diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp
index a1c1c4ce6132..3342148461ad 100644
--- a/test/CXX/drs/dr3xx.cpp
+++ b/test/CXX/drs/dr3xx.cpp
@@ -908,18 +908,21 @@ namespace dr372 { // dr372: no
}
}
-namespace dr373 { // dr373: no
- // FIXME: This is valid.
- namespace X { int dr373; } // expected-note 2{{here}}
+namespace dr373 { // dr373: 5
+ namespace X { int dr373; }
struct dr373 { // expected-note {{here}}
void f() {
- using namespace dr373::X; // expected-error {{no namespace named 'X' in 'dr373::dr373'}}
+ using namespace dr373::X;
int k = dr373; // expected-error {{does not refer to a value}}
- namespace Y = dr373::X; // expected-error {{no namespace named 'X' in 'dr373::dr373'}}
+ namespace Y = dr373::X;
k = Y::dr373;
}
};
+
+ struct A { struct B {}; }; // expected-note 2{{here}}
+ namespace X = A::B; // expected-error {{expected namespace name}}
+ using namespace A::B; // expected-error {{expected namespace name}}
}
namespace dr374 { // dr374: yes c++11
diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp
index 6046c4afefd5..3ea226a745f6 100644
--- a/test/CXX/drs/dr4xx.cpp
+++ b/test/CXX/drs/dr4xx.cpp
@@ -35,9 +35,7 @@ namespace dr401 { // dr401: yes
};
A<B> *b; // expected-note {{default argument}}
- // FIXME: We're missing the "in instantiation of" note for the default
- // argument here.
- A<D> *d;
+ A<D> *d; // expected-note {{in instantiation of default argument}}
struct E {
template<class T, class U = typename T::type> class A : public T {};
diff --git a/test/CXX/drs/dr5xx.cpp b/test/CXX/drs/dr5xx.cpp
index 89e404f5fd6d..97b40b8b7c26 100644
--- a/test/CXX/drs/dr5xx.cpp
+++ b/test/CXX/drs/dr5xx.cpp
@@ -877,13 +877,25 @@ namespace dr583 { // dr583: 4
namespace dr585 { // dr585: yes
template<typename> struct T;
struct A {
- friend T; // expected-error {{requires a type specifier}} expected-error {{can only be classes or functions}}
+ friend T;
+#if __cplusplus <= 201402L
+ // expected-error@-2 {{requires a type specifier}} expected-error@-2 {{can only be classes or functions}}
+#else
+ // expected-error@-4 {{use of class template 'T' requires template arguments; argument deduction not allowed in friend declaration}}
+ // expected-note@-7 {{here}}
+#endif
// FIXME: It's not clear whether the standard allows this or what it means,
// but the DR585 writeup suggests it as an alternative.
template<typename U> friend T<U>; // expected-error {{must use an elaborated type}}
};
template<template<typename> class T> struct B {
- friend T; // expected-error {{requires a type specifier}} expected-error {{can only be classes or functions}}
+ friend T;
+#if __cplusplus <= 201402L
+ // expected-error@-2 {{requires a type specifier}} expected-error@-2 {{can only be classes or functions}}
+#else
+ // expected-error@-4 {{use of template template parameter 'T' requires template arguments; argument deduction not allowed in friend declaration}}
+ // expected-note@-6 {{here}}
+#endif
template<typename U> friend T<U>; // expected-error {{must use an elaborated type}}
};
}
@@ -942,7 +954,7 @@ namespace dr591 { // dr591: no
template<typename T> struct A<T>::B::C : A<T> {
// FIXME: Should find member of non-dependent base class A<T>.
- M m; // expected-error {{incomplete type 'M' (aka 'void'}}
+ M m; // expected-error {{incomplete type 'dr591::A::B::M' (aka 'void'}}
};
}
diff --git a/test/CXX/expr/expr.post/expr.type.conv/p1.cpp b/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
new file mode 100644
index 000000000000..f3608bc378bc
--- /dev/null
+++ b/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+template<typename T> struct A { // expected-note 2{{candidate}}
+ T t, u;
+};
+template<typename T> A(T, T) -> A<T>; // expected-note {{deduced conflicting types for parameter 'T'}}
+template<typename T> A(A<T>) -> A<T>; // expected-note {{requires 1 argument, but 2 were provided}}
+
+A a = A{1, 2};
+A b = A{3, 4.0}; // expected-error {{no viable constructor or deduction guide}}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
index 4a2a4f3d7353..e7fce11abc5e 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify
void odr_used() {
int i = 17;
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
index 8bb707e0dbc7..b55beb7d4ed7 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify
void f2() {
int i = 1;
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
index 94f8111015aa..905192ff830b 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify
struct X {
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
index 93c2805497f3..72cf93be5190 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify
// expected-no-diagnostics
template<typename T, typename U>
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
index 1dbcbf498031..a8b40249f0f0 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture -verify
struct MoveOnly {
MoveOnly(MoveOnly&&);
diff --git a/test/CXX/over/over.match/over.match.best/p1.cpp b/test/CXX/over/over.match/over.match.best/p1.cpp
index 59e3dac74283..fad5bf9a72ee 100644
--- a/test/CXX/over/over.match/over.match.best/p1.cpp
+++ b/test/CXX/over/over.match/over.match.best/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
// expected-no-diagnostics
template<typename T> int &f0(T*, int);
@@ -12,6 +12,28 @@ void test_f0(int* ip, void *vp) {
float &fr = f0(vp, 0);
}
+namespace deduction_guide_example {
+ template<typename T> struct A {
+ A(T, int*);
+ A(A<T>&, int*);
+ enum { value };
+ };
+
+ template<typename T> struct remove_ref_impl;
+ template<typename T> struct remove_ref_impl<T&> { using type = T; };
+ template<typename T> using remove_ref = typename remove_ref_impl<T>::type;
+
+ // FIXME: The standard's example is wrong; we add a remove_ref<...> here to
+ // fix it.
+ template<typename T, int N = remove_ref<T>::value> A(T&&, int*) -> A<T>;
+ A a{1, 0};
+ extern A<int> a;
+ A b{a, 0};
+
+ A<int> *pa = &a;
+ A<A<int>&> *pb = &b;
+}
+
// Partial ordering of function template specializations will be tested
// elsewhere
// FIXME: Initialization by user-defined conversion is tested elsewhere
diff --git a/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
new file mode 100644
index 000000000000..fe1b6a63d75b
--- /dev/null
+++ b/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -verify -std=c++1z %s
+
+namespace Explicit {
+ // Each notional constructor is explicit if the function or function template
+ // was generated from a constructor or deduction-guide that was declared explicit.
+ template<typename T> struct A {
+ A(T);
+ A(T*);
+ };
+ template<typename T> A(T) -> A<T>;
+ template<typename T> explicit A(T*) -> A<T>; // expected-note {{explicit}}
+
+ int *p;
+ A a(p);
+ A b = p;
+ A c{p};
+ A d = {p}; // expected-error {{selected an explicit deduction guide}}
+
+ using X = A<int>;
+ using Y = A<int*>;
+
+ using X = decltype(a);
+ using Y = decltype(b);
+ using X = decltype(c);
+}
diff --git a/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp b/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp
new file mode 100644
index 000000000000..4ed1d30b83d5
--- /dev/null
+++ b/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+namespace std_example {
+ template <class T> struct A {
+ explicit A(const T &, ...) noexcept; // expected-note {{explicit}} expected-note 2{{candidate}}
+ A(T &&, ...); // expected-note 2{{candidate}}
+ };
+
+ int i;
+ A a1 = {i, i}; // expected-error {{class template argument deduction for 'A' selected an explicit constructor for copy-list-initialization}}
+ A a2{i, i};
+ A a3{0, i};
+ A a4 = {0, i};
+
+ template <class T> A(const T &, const T &) -> A<T &>; // expected-note 2{{candidate}}
+ template <class T> explicit A(T &&, T &&) -> A<T>; // expected-note {{explicit deduction guide declared here}}
+
+ // FIXME: The standard gives an incorrect explanation for why a5, a7, and a8 are ill-formed.
+ A a5 = {0, 1}; // expected-error {{class template argument deduction for 'A' selected an explicit deduction guide}}
+ A a6{0, 1};
+ A a7 = {0, i}; // expected-error {{ambiguous deduction}}
+ A a8{0, i}; // expected-error {{ambiguous deduction}}
+
+ template <class T> struct B {
+ template <class U> using TA = T;
+ template <class U> B(U, TA<U>);
+ };
+ B b{(int *)0, (char *)0};
+}
+
+namespace check {
+ using namespace std_example;
+ template<typename T, typename U> constexpr bool same = false;
+ template<typename T> constexpr bool same<T, T> = true;
+
+ static_assert(same<decltype(a2), A<int>>);
+ static_assert(same<decltype(a3), A<int>>);
+ static_assert(same<decltype(a4), A<int>>);
+ static_assert(same<decltype(a6), A<int>>);
+ static_assert(same<decltype(b), B<char*>>);
+}
diff --git a/test/CXX/special/class.dtor/p10-0x.cpp b/test/CXX/special/class.dtor/p10-0x.cpp
index 3b8a0ad4d6a7..3be0a98d47d7 100644
--- a/test/CXX/special/class.dtor/p10-0x.cpp
+++ b/test/CXX/special/class.dtor/p10-0x.cpp
@@ -33,7 +33,7 @@ void a(const A *x, int i, int *pi) {
expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
i.~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
pi->~decltype(int())();
- pi.~decltype(int())(); // expected-error{{the type of object expression ('int *') does not match the type being destroyed ('decltype(int())' (aka 'int')) in pseudo-destructor expression}}
+ pi.~decltype(int())(); // expected-error{{member reference type 'int *' is a pointer; did you mean to use '->'?}}
pi.~decltype(intp())();
pi->~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp b/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
index 4960a2bac20a..87c22a0d7e94 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
@@ -61,7 +61,7 @@ struct X {
template<class... Members>
template<int i>
-X<Members...>::get_t<i> X<Members...>::get()
+typename X<Members...>::template get_t<i> X<Members...>::get()
{
return 0;
}
diff --git a/test/CXX/temp/temp.deduct.guide/p1.cpp b/test/CXX/temp/temp.deduct.guide/p1.cpp
new file mode 100644
index 000000000000..c0a2ba1129e2
--- /dev/null
+++ b/test/CXX/temp/temp.deduct.guide/p1.cpp
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s -DCLASS
+
+#ifdef CLASS
+struct Outer {
+#endif
+
+template<typename> struct A {};
+
+// Valid forms.
+A(int(&)[1]) -> A<int>;
+explicit A(int(&)[2]) -> A<int>;
+
+// Declarator pieces are not OK.
+*A(int(&)[3]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}}
+&A(int(&)[4]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}}
+A(int(&)[5])[3] -> A<int>;
+#ifdef CLASS // FIXME: These diagnostics are both pretty bad.
+// expected-error@-2 {{function cannot return array type}} expected-error@-2 {{';'}}
+#else
+// expected-error@-4 {{expected function body after function declarator}}
+#endif
+
+(A[3])(int(&)[5][1]) -> A<int>; // expected-error {{'<deduction guide for A>' cannot be the name of a variable}}
+#ifndef CLASS
+// expected-error@-2 {{declared as array of functions}}
+#endif
+(*A)(int(&)[5][2]) -> A<int>; // expected-error {{'<deduction guide for A>' cannot be the name of a variable}}
+(&A)(int(&)[5][3]) -> A<int>; // expected-error {{'<deduction guide for A>' cannot be the name of a variable}}
+(*A(int))(int(&)[5][4]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}}
+
+// (Pending DR) attributes and parens around the declarator-id are OK.
+[[deprecated]] A(int(&)[6]) [[]] -> A<int> [[]];
+A [[]] (int(&)[7]) -> A<int>;
+(A)(int(&)[8]) -> A<int>;
+
+// ... but the trailing-return-type is part of the function-declarator as normal
+(A(int(&)[9])) -> A<int>;
+#ifdef CLASS // FIXME: These diagnostics are both pretty bad.
+// expected-error@-2 {{deduction guide declaration without trailing return type}} expected-error@-2 {{';'}}
+#else
+// expected-error@-4 {{expected function body after function declarator}}
+#endif
+(A(int(&)[10]) -> A<int>); // expected-error {{trailing return type may not be nested within parentheses}}
+
+// A trailing-return-type is mandatory.
+A(int(&)[11]); // expected-error {{deduction guide declaration without trailing return type}}
+
+// No type specifier is permitted; we don't even parse such cases as a deduction-guide.
+int A(int) -> A<int>; // expected-error {{function with trailing return type must specify return type 'auto', not 'int'}}
+template<typename T> struct B {}; // expected-note {{here}}
+auto B(int) -> B<int>; // expected-error {{redefinition of 'B' as different kind of symbol}}
+
+// No storage class specifier, function specifier, ...
+friend A(int(&)[20]) -> A<int>;
+#ifdef CLASS
+// expected-error@-2 {{cannot declare a deduction guide as a friend}}
+#else
+// expected-error@-4 {{'friend' used outside of class}}
+#endif
+typedef A(int(&)[21]) -> A<int>; // expected-error {{deduction guide cannot be declared 'typedef'}}
+constexpr A(int(&)[22]) -> A<int>; // expected-error {{deduction guide cannot be declared 'constexpr'}}
+inline A(int(&)[23]) -> A<int>; // expected-error {{deduction guide cannot be declared 'inline'}}
+static A(int(&)[24]) -> A<int>; // expected-error {{deduction guide cannot be declared 'static'}}
+thread_local A(int(&)[25]) -> A<int>; // expected-error {{'thread_local' is only allowed on variable declarations}}
+extern A(int(&)[26]) -> A<int>;
+#ifdef CLASS
+// expected-error@-2 {{storage class specified for a member}}
+#else
+// expected-error@-4 {{deduction guide cannot be declared 'extern'}}
+#endif
+mutable A(int(&)[27]) -> A<int>; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}}
+virtual A(int(&)[28]) -> A<int>; // expected-error {{'virtual' can only appear on non-static member functions}}
+const A(int(&)[28]) -> A<int>; // expected-error {{deduction guide cannot be declared 'const'}}
+
+const volatile static constexpr inline A(int(&)[29]) -> A<int>; // expected-error {{deduction guide cannot be declared 'static inline constexpr const volatile'}}
+
+A(int(&)[30]) const -> A<int>; // expected-error {{deduction guide cannot have 'const' qualifier}}
+
+// No definition is allowed.
+A(int(&)[40]) -> A<int> {} // expected-error {{deduction guide cannot have a function definition}}
+A(int(&)[41]) -> A<int> = default; // expected-error {{deduction guide cannot have a function definition}} expected-error {{only special member functions may be defaulted}}
+A(int(&)[42]) -> A<int> = delete; // expected-error {{deduction guide cannot have a function definition}}
+A(int(&)[43]) -> A<int> try {} catch (...) {} // expected-error {{deduction guide cannot have a function definition}}
+
+#ifdef CLASS
+};
+#endif
+
+namespace ExplicitInst {
+ // Explicit instantiation / specialization is not permitted.
+ template<typename T> struct B {};
+ template<typename T> B(T) -> B<T>;
+ template<> B(int) -> B<int>; // expected-error {{deduction guide cannot be explicitly specialized}}
+ extern template B(float) -> B<float>; // expected-error {{deduction guide cannot be explicitly instantiated}}
+ template B(char) -> B<char>; // expected-error {{deduction guide cannot be explicitly instantiated}}
+
+ // An attempt at partial specialization doesn't even parse as a deduction-guide.
+ template<typename T> B<T*>(T*) -> B<T*>; // expected-error 1+{{}} expected-note 0+{{}}
+
+ struct X {
+ template<typename T> struct C {};
+ template<typename T> C(T) -> C<T>;
+ template<> C(int) -> C<int>; // expected-error {{explicit specialization of '<deduction guide for C>' in class scope}}
+ extern template C(float) -> C<float>; // expected-error {{expected member name or ';'}}
+ template C(char) -> C<char>; // expected-error {{expected '<' after 'template'}}
+ };
+}
diff --git a/test/CXX/temp/temp.deduct.guide/p2.cpp b/test/CXX/temp/temp.deduct.guide/p2.cpp
new file mode 100644
index 000000000000..3549755ff0f2
--- /dev/null
+++ b/test/CXX/temp/temp.deduct.guide/p2.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+// expected-no-diagnostics
+
+namespace std_example {
+ template<typename T, typename U = int> struct S {
+ T data;
+ };
+ template<typename U> S(U) -> S<typename U::type>;
+
+ struct A {
+ using type = short;
+ operator type();
+ };
+ S x{A()};
+}
diff --git a/test/CXX/temp/temp.deduct.guide/p3.cpp b/test/CXX/temp/temp.deduct.guide/p3.cpp
new file mode 100644
index 000000000000..e12f7b6ef255
--- /dev/null
+++ b/test/CXX/temp/temp.deduct.guide/p3.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -std=c++1z %s -verify
+
+// The same restrictions apply to the parameter-declaration-clause of a
+// deduction guide as in a function declaration.
+template<typename T> struct A {};
+A(void) -> A<int>; // ok
+A(void, int) -> A<int>; // expected-error {{'void' must be the first and only parameter if specified}}
+
+// We interpret this as also extending to the validity of redeclarations. It's
+// a bit of a stretch (OK, a lot of a stretch) but it gives desirable answers.
+A() -> A<int>; // ok, redeclaration
+
+A() -> A<int>; // expected-note {{previous}}
+A() -> A<float>; // FIXME: "functions" is a poor term. expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+template<typename T> A(T) -> A<typename T::foo>;
+template<typename T> A(T) -> A<typename T::bar>; // ok, can overload on return type (SFINAE applies)
+
+A(long) -> A<int>;
+template<typename T = int> A(long) -> A<char>; // ok, non-template beats template as usual
+
+// (Pending DR) The template-name shall name a class template.
+template<typename T> using B = A<T>; // expected-note {{template}}
+B() -> B<int>; // expected-error {{cannot specify deduction guide for alias template 'B'}}
+// FIXME: expected-error@-1 {{declarator requires an identifier}}
+template<typename T> int C;
+C() -> int; // expected-error {{requires a type specifier}}
+template<typename T> void D();
+D() -> int; // expected-error {{requires a type specifier}}
+template<template<typename> typename TT> struct E { // expected-note 2{{template}}
+ // FIXME: Should only diagnose this once!
+ TT(int) -> TT<int>; // expected-error 2{{cannot specify deduction guide for template template parameter 'TT'}} expected-error {{requires an identifier}}
+};
+
+A(int) -> int; // expected-error {{deduced type 'int' of deduction guide is not a specialization of template 'A'}}
+template<typename T> A(T) -> B<T>; // expected-error {{deduced type 'B<T>' (aka 'A<type-parameter-0-0>') of deduction guide is not written as a specialization of template 'A'}}
+template<typename T> A(T*) -> const A<T>; // expected-error {{deduced type 'const A<T>' of deduction guide is not a specialization of template 'A'}}
+
+// A deduction-guide shall be declared in the same scope as the corresponding
+// class template.
+namespace WrongScope {
+ namespace {
+ template<typename T> struct AnonNS1 {}; // expected-note {{here}}
+ AnonNS1(float) -> AnonNS1<float>; // ok
+ }
+ AnonNS1(int) -> AnonNS1<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::}}
+ template<typename T> struct AnonNS2 {}; // expected-note {{here}}
+ namespace {
+ AnonNS1(char) -> AnonNS1<char>; // ok
+ AnonNS2(int) -> AnonNS2<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::AnonNS2'}}
+ }
+ namespace N {
+ template<typename T> struct NamedNS1 {}; // expected-note {{here}}
+ template<typename T> struct NamedNS2 {}; // expected-note {{here}}
+ }
+ using N::NamedNS1;
+ NamedNS1(int) -> NamedNS1<int>; // expected-error {{deduction guide must be declared in the same scope as template}}
+ using namespace N;
+ NamedNS2(int) -> NamedNS2<int>; // expected-error {{deduction guide must be declared in the same scope as template}}
+ struct ClassMemberA {
+ template<typename T> struct X {}; // expected-note {{here}}
+ };
+ struct ClassMemberB : ClassMemberA {
+ X(int) -> X<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::ClassMemberA::X'}}
+ };
+ template<typename T> struct Local {};
+ void f() {
+ Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}}
+ using WrongScope::Local;
+ Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}}
+ }
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
index e470dd016644..ebff0a1df4e7 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
@@ -1,9 +1,39 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
+// 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 __cplusplus > 201402L
+namespace ClassTemplateParamNotForwardingRef {
+ // This is not a forwarding reference.
+ template<typename T> struct A { // expected-note {{candidate}}
+ A(T&&); // expected-note {{no known conversion from 'int' to 'int &&'}}
+ };
+ int n;
+ A a = n; // expected-error {{no viable constructor or deduction guide}}
-// 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.
+ A b = 0;
+ A<int> *pb = &b;
+
+ // This is a forwarding reference.
+ template<typename T> A(T&&) -> A<T>;
+ A c = n;
+ A<int&> *pc = &c;
+
+ A d = 0;
+ A<int> *pd = &d;
+
+ template<typename T = void> struct B {
+ // This is a forwarding reference.
+ template<typename U> B(U &&);
+ };
+ B e = n;
+ B<void> *pe = &e;
+}
+#endif
+
+// 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.
template<typename T> struct X { };
template<typename T> X<T> f0(T&&);
@@ -43,4 +73,21 @@ namespace std_example {
int n1 = f(i);
int n2 = f(0);
int n3 = g(i); // expected-error{{no matching function for call to 'g'}}
+
+#if __cplusplus > 201402L
+ template<class T> struct A { // expected-note {{candidate}}
+ template<class U>
+ A(T &&, U &&, int *); // expected-note {{[with T = int, U = int] not viable: no known conversion from 'int' to 'int &&'}}
+ A(T &&, int *); // expected-note {{requires 2}}
+ };
+ template<class T> A(T &&, int *) -> A<T>; // expected-note {{requires 2}}
+
+ int *ip;
+ A a{i, 0, ip}; // expected-error {{no viable constructor or deduction guide}}
+ A a0{0, 0, ip};
+ A a2{i, ip};
+
+ A<int> &a0r = a0;
+ A<int&> &a2r = a2;
+#endif
}
diff --git a/test/CXX/temp/temp.res/p3.cpp b/test/CXX/temp/temp.res/p3.cpp
new file mode 100644
index 000000000000..ea87b8d10546
--- /dev/null
+++ b/test/CXX/temp/temp.res/p3.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -verify %s -std=c++11
+
+template<typename T> struct A {
+ template<typename U> struct B;
+ template<typename U> using C = U; // expected-note {{here}}
+};
+
+struct X {
+ template<typename T> X(T);
+ struct Y {
+ template<typename T> Y(T);
+ };
+};
+
+template<typename T> A // expected-error {{missing 'typename' prior to dependent type template name 'A<T>::B'}}
+ <T>::B<T> f1();
+template<typename T> A<T>::C<T> f2(); // expected-error {{missing 'typename' prior to dependent type template name 'A<T>::C'}}
+
+// FIXME: Should these cases really be valid? There doesn't appear to be a rule prohibiting them...
+template<typename T> A<T>::C<X>::X(T) {}
+template<typename T> A<T>::C<X>::X::Y::Y(T) {}
+
+// FIXME: This is ill-formed
+template<typename T> int A<T>::B<T>::*f3() {}
+template<typename T> int A<T>::C<X>::*f4() {}
+
+// FIXME: This is valid
+template<typename T> int A<T>::template C<int>::*f5() {} // expected-error {{has no members}}
+
+template<typename T> template<typename U> struct A<T>::B {
+ friend A<T>::C<T> f6(); // ok, same as 'friend T f6();'
+
+ // FIXME: Error recovery here is awful; we decide that the template-id names
+ // a type, and then complain about the rest of the tokens, and then complain
+ // that we didn't get a function declaration.
+ friend A<U>::C<T> f7(); // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}} expected-error 3{{}}
+ friend A<U>::template C<T> f8(); // expected-error 3{{}}
+};
diff --git a/test/CXX/temp/temp.res/temp.local/p1.cpp b/test/CXX/temp/temp.res/temp.local/p1.cpp
index f6ef636daa56..faa85cb5fce3 100644
--- a/test/CXX/temp/temp.res/temp.local/p1.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p1.cpp
@@ -1,12 +1,55 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
-// C++0x [temp.local]p1:
+// C++1z [temp.local]p1:
// Like normal (non-template) classes, class templates have an
-// injected-class-name (Clause 9). The injected-class-name can be used with
-// or without a template-argument-list. When it is used without
-// a template-argument-list, it is equivalent to the injected-class-name
-// followed by the template-parameters of the class template enclosed in <>.
+// injected-class-name (Clause 9). The injected-class-name can
+// be used as a template-name or a type-name.
+
+template<typename> char id;
+
+template<typename> struct TempType {};
+template<template<typename> class> struct TempTemp {};
+
+template<typename> void use(int&); // expected-note {{invalid explicitly-specified argument}} expected-note {{no known conversion}}
+template<template<typename> class> void use(float&); // expected-note 2{{no known conversion}}
+template<int> void use(char&); // expected-note 2{{invalid explicitly-specified argument}}
+
+template<typename T> struct A {
+ template<typename> struct C {};
+ struct B : C<T> {
+ // When it is used with a template-argument-list,
+ A<int> *aint;
+ typename B::template C<int> *cint;
+
+ // as a template-argument for a template template-parameter,
+ TempTemp<A> a_as_temp;
+ TempTemp<B::template C> c_as_temp;
+
+ // or as the final identifier in the elaborated-type-specifier of a friend
+ // class template declaration,
+ template<typename U> friend struct A;
+ // it refers to the class template itself.
+
+ // Otherwise, it is equivalent to the template-name followed by the
+ // template-parameters of the class template enclosed in <>.
+ A *aT;
+ typename B::C *cT;
+ TempType<A> a_as_type;
+ TempType<typename B::C> c_as_type;
+ friend struct A;
+ friend struct B::C;
+
+ void f(T &t) {
+ use<A>(t); // expected-error {{no matching function}}
+ if constexpr (&id<T> != &id<int>)
+ use<B::template C>(t); // expected-error {{no matching function}}
+ }
+ };
+};
+
+template struct A<int>;
+template struct A<float>;
+template struct A<char>; // expected-note {{instantiation of}}
template <typename T> struct X0 {
X0();
diff --git a/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp b/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
index 7eb5e3744d18..425d527e5212 100644
--- a/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
+++ b/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
@@ -9,7 +9,7 @@ T pi = T(3.1415926535897932385); // expected-note {{template is declared here}}
template int pi<int>;
#ifndef FIXING
-template float pi<>; // expected-error {{too few template arguments for template 'pi'}}
+template float pi<>; // expected-error {{too few template arguments for variable template 'pi'}}
template double pi_var0; // expected-error {{explicit instantiation of 'pi_var0' does not refer to a function template, variable template, member function, member class, or static data member}}
#endif
diff --git a/test/CodeCompletion/auto_type.c b/test/CodeCompletion/auto_type.c
new file mode 100644
index 000000000000..3fcfff0dcfc9
--- /dev/null
+++ b/test/CodeCompletion/auto_type.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -code-completion-at=%s:3:1 %s | FileCheck %s
+void func() {
+
+}
+// CHECK: COMPLETION: __auto_type
diff --git a/test/CodeCompletion/keywords.cpp b/test/CodeCompletion/keywords.cpp
new file mode 100644
index 000000000000..6e5824c2f183
--- /dev/null
+++ b/test/CodeCompletion/keywords.cpp
@@ -0,0 +1,79 @@
+int function(int x) {
+ return x + 1;
+}
+
+int variable = 0;
+
+class Class {
+public:
+ Class() { }
+
+ int method(int x) {
+ return x + 1;
+ }
+
+ virtual void virtualMethod() {
+ }
+
+ static void staticMethod() {
+ }
+
+ static int staticVar;
+};
+
+class SubClass : public Class {
+ void virtualMethod() override final {
+ }
+};
+
+struct Struct {
+};
+
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:1:1 %s | FileCheck --check-prefix=CHECK-TOP-LEVEL %s
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:5:1 %s | FileCheck --check-prefix=CHECK-TOP-LEVEL %s
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:11:1 %s | FileCheck --check-prefix=CHECK-TOP-LEVEL %s
+// CHECK-TOP-LEVEL: alignas(<#expression#>)
+// CHECK-TOP-LEVEL: constexpr
+// CHECK-TOP-LEVEL: static_assert(<#expression#>, <#message#>)
+// CHECK-TOP-LEVEL: thread_local
+// CHECK-TOP-LEVEL-NOT: final
+// CHECK-TOP-LEVEL-NOT: noexcept
+
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:1:14 %s | FileCheck --check-prefix=CHECK-PARAM %s
+// CHECK-PARAM-NOT: alignas
+// CHECK-PARAM-NOT: constexpr
+// CHECK-PARAM-NOT: final
+// CHECK-PARAM-NOT: thread_local
+
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:21:10 %s | FileCheck --check-prefix=CHECK-STATICVAR1 %s
+// CHECK-STATICVAR1: constexpr
+// CHECK-STATICVAR1: thread_local
+
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:7:13 %s | FileCheck --check-prefix=CHECK-CLASS-QUALIFIER %s
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:24:16 %s | FileCheck --check-prefix=CHECK-CLASS-QUALIFIER %s
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:29:15 %s | FileCheck --check-prefix=CHECK-CLASS-QUALIFIER %s
+// CHECK-CLASS-QUALIFIER: final
+
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:1:21 %s | FileCheck --check-prefix=CHECK-FUNCTION-QUALIFIER %s
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:9:11 %s | FileCheck --check-prefix=CHECK-FUNCTION-QUALIFIER %s
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:18:30 %s | FileCheck --check-prefix=CHECK-FUNCTION-QUALIFIER %s
+// CHECK-FUNCTION-QUALIFIER: noexcept
+// CHECK-FUNCTION-QUALIFIER-NOT: final
+// CHECK-FUNCTION-QUALIFIER-NOT: override
+
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:11:21 %s | FileCheck --check-prefix=CHECK-METHOD-QUALIFIER %s
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:15:32 %s | FileCheck --check-prefix=CHECK-METHOD-QUALIFIER %s
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:25:24 %s | FileCheck --check-prefix=CHECK-METHOD-QUALIFIER %s
+// CHECK-METHOD-QUALIFIER: final
+// CHECK-METHOD-QUALIFIER: noexcept
+// CHECK-METHOD-QUALIFIER: override
+
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:25:33 %s | FileCheck --check-prefix=CHECK-OVERRIDE-SPECIFIED %s
+// CHECK-OVERRIDE-SPECIFIED: final
+// CHECK-OVERRIDE-SPECIFIED: noexcept
+// CHECK-OVERRIDE-SPECIFIED-NOT: override
+
+// RUN: %clang_cc1 -std=c++11 -code-completion-at=%s:25:39 %s | FileCheck --check-prefix=CHECK-OVERRIDE-FINAL-SPECIFIED %s
+// CHECK-OVERRIDE-FINAL-SPECIFIED: noexcept
+// CHECK-OVERRIDE-FINAL-SPECIFIED-NOT: final
+// CHECK-OVERRIDE-FINAL-SPECIFIED-NOT: override
diff --git a/test/CodeCompletion/member-access.cpp b/test/CodeCompletion/member-access.cpp
index 8195f764fbb6..66872272ee6d 100644
--- a/test/CodeCompletion/member-access.cpp
+++ b/test/CodeCompletion/member-access.cpp
@@ -37,6 +37,17 @@ struct Test1 {
}
};
+struct Foo {
+ void foo() const;
+ static void foo(bool);
+};
+
+struct Bar {
+ void foo(bool param) {
+ Foo::foo( );// unresolved member expression with an implicit base
+ }
+};
+
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:29:6 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: Base1 : Base1::
// CHECK-CC1: member1 : [#int#][#Base1::#]member1
@@ -52,3 +63,6 @@ struct Test1 {
// Make sure this doesn't crash
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:36:7 %s -verify
+
+// Make sure this also doesn't crash
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:47:14 %s
diff --git a/test/CodeCompletion/ordinary-name-cxx11.cpp b/test/CodeCompletion/ordinary-name-cxx11.cpp
index 8e6f38322384..34c3bf96a9d5 100644
--- a/test/CodeCompletion/ordinary-name-cxx11.cpp
+++ b/test/CodeCompletion/ordinary-name-cxx11.cpp
@@ -39,10 +39,12 @@ void foo() {
// CHECK-CC1-NEXT: COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
// CHECK-CC1-NEXT: COMPLETION: Pattern : [#size_t#]sizeof...(<#parameter-pack#>)
// CHECK-CC1-NEXT: COMPLETION: static
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : static_assert(<#expression#>, <#message#>)
// CHECK-CC1-NEXT: COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
// CHECK-CC1-NEXT: COMPLETION: struct
// CHECK-CC1-NEXT: COMPLETION: Pattern : switch(<#condition#>){
// CHECK-CC1: COMPLETION: t : t
+ // CHECK-CC1-NEXT: COMPLETION: thread_local
// CHECK-CC1-NEXT: COMPLETION: Pattern : [#void#]throw <#expression#>
// CHECK-CC1-NEXT: COMPLETION: Pattern : [#bool#]true
// CHECK-CC1-NEXT: COMPLETION: Pattern : try{<#statements#>
@@ -72,6 +74,7 @@ void foo() {
// CHECK-CC2-NEXT: COMPLETION: char32
// CHECK-CC2-NEXT: COMPLETION: class
// CHECK-CC2-NEXT: COMPLETION: const
+ // CHECK-CC2-NEXT: COMPLETION: constexpr
// CHECK-CC2-NEXT: COMPLETION: Pattern : decltype(<#expression#>)
// CHECK-CC2-NEXT: COMPLETION: double
// CHECK-CC2-NEXT: COMPLETION: enum
@@ -86,10 +89,12 @@ void foo() {
// CHECK-CC2-NEXT: COMPLETION: short
// CHECK-CC2-NEXT: COMPLETION: signed
// CHECK-CC2-NEXT: COMPLETION: static
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : static_assert(<#expression#>, <#message#>)
// CHECK-CC2-NEXT: COMPLETION: struct
// CHECK-CC2-NEXT: COMPLETION: t : t
// CHECK-CC2-NEXT: COMPLETION: Pattern : template <#declaration#>
// CHECK-CC2-NEXT: COMPLETION: Pattern : template<<#parameters#>>
+ // CHECK-CC2-NEXT: COMPLETION: thread_local
// CHECK-CC2-NEXT: COMPLETION: TYPEDEF : TYPEDEF
// CHECK-CC2-NEXT: COMPLETION: Pattern : typedef <#type#> <#name#>
// CHECK-CC2-NEXT: COMPLETION: Pattern : typename <#qualifier#>::<#name#>
@@ -111,6 +116,7 @@ void foo() {
// CHECK-CC3-NEXT: COMPLETION: char32_t
// CHECK-CC3-NEXT: COMPLETION: class
// CHECK-CC3-NEXT: COMPLETION: const
+ // CHECK-CC3-NEXT: COMPLETION: constexpr
// CHECK-CC3-NEXT: COMPLETION: Pattern : decltype(<#expression#>)
// CHECK-CC3-NEXT: COMPLETION: double
// CHECK-CC3-NEXT: COMPLETION: enum
@@ -129,8 +135,10 @@ void foo() {
// CHECK-CC3-NEXT: COMPLETION: short
// CHECK-CC3-NEXT: COMPLETION: signed
// CHECK-CC3-NEXT: COMPLETION: static
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : static_assert(<#expression#>, <#message#>)
// CHECK-CC3-NEXT: COMPLETION: struct
// CHECK-CC3-NEXT: COMPLETION: Pattern : template<<#parameters#>>
+ // CHECK-CC3-NEXT: COMPLETION: thread_local
// CHECK-CC3-NEXT: COMPLETION: Pattern : typedef <#type#> <#name#>
// CHECK-CC3-NEXT: COMPLETION: Pattern : typename <#qualifier#>::<#name#>
// CHECK-CC3-NEXT: COMPLETION: Pattern : typeof <#expression#>
@@ -227,6 +235,7 @@ void foo() {
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : [#size_t#]sizeof...(<#parameter-pack#>)
// CHECK-NO-RTTI-NEXT: COMPLETION: static
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : static_assert(<#expression#>, <#message#>)
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
// CHECK-NO-RTTI-NEXT: COMPLETION: struct
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : switch(<#condition#>){
diff --git a/test/CodeCompletion/pragma-macro-token-caching.c b/test/CodeCompletion/pragma-macro-token-caching.c
new file mode 100644
index 000000000000..432706e85ceb
--- /dev/null
+++ b/test/CodeCompletion/pragma-macro-token-caching.c
@@ -0,0 +1,18 @@
+
+#define Outer(action) action
+
+void completeParam(int param) {
+ ;
+ Outer(__extension__({ _Pragma("clang diagnostic push") }));
+ param;
+}
+
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:7:1 %s | FileCheck %s
+// CHECK: param : [#int#]param
+
+void completeParamPragmaError(int param) {
+ Outer(__extension__({ _Pragma(2) })); // expected-error {{_Pragma takes a parenthesized string literal}}
+ param;
+}
+
+// RUN: %clang_cc1 -fsyntax-only -verify -code-completion-at=%s:16:1 %s | FileCheck %s
diff --git a/test/CodeGen/2006-05-19-SingleEltReturn.c b/test/CodeGen/2006-05-19-SingleEltReturn.c
index 819237ce53be..dfc23f84ab42 100644
--- a/test/CodeGen/2006-05-19-SingleEltReturn.c
+++ b/test/CodeGen/2006-05-19-SingleEltReturn.c
@@ -1,12 +1,13 @@
// Test returning a single element aggregate value containing a double.
+// RUN: %clang_cc1 -triple i686-linux %s -emit-llvm -o - | FileCheck %s --check-prefix=X86_32
// RUN: %clang_cc1 %s -emit-llvm -o -
struct X {
double D;
};
-struct Y {
- struct X x;
+struct Y {
+ struct X x;
};
struct Y bar();
@@ -21,3 +22,9 @@ struct Y bar() {
return a;
}
+
+// X86_32: define void @foo(%struct.Y* %P)
+// X86_32: call void @bar(%struct.Y* sret %{{[^),]*}})
+
+// X86_32: define void @bar(%struct.Y* noalias sret %{{[^,)]*}})
+// X86_32: ret void
diff --git a/test/CodeGen/Inputs/debug-info-macro.h b/test/CodeGen/Inputs/debug-info-macro.h
new file mode 100644
index 000000000000..f71d5c3343d2
--- /dev/null
+++ b/test/CodeGen/Inputs/debug-info-macro.h
@@ -0,0 +1,12 @@
+
+#ifdef D1
+/*Line 3*/ #define A(x, y, z) (x)
+#endif
+
+#ifdef D2
+/*Line 7*/ #define A(x, y, z) (y)
+#endif
+
+#ifdef A
+/*Line 11*/ #undef A
+#endif
diff --git a/test/CodeGen/Inputs/pgo-sample-thinlto-summary.prof b/test/CodeGen/Inputs/pgo-sample-thinlto-summary.prof
new file mode 100644
index 000000000000..d3680dc1f724
--- /dev/null
+++ b/test/CodeGen/Inputs/pgo-sample-thinlto-summary.prof
@@ -0,0 +1,4 @@
+bar:100:100
+ 2: 2000 foo:2000
+icp:100:100
+ 1: 1000 unroll:1000
diff --git a/test/CodeGen/aarch64-neon-intrinsics.c b/test/CodeGen/aarch64-neon-intrinsics.c
index 2ffbcdce372c..54877e9d8cd9 100644
--- a/test/CodeGen/aarch64-neon-intrinsics.c
+++ b/test/CodeGen/aarch64-neon-intrinsics.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -fallow-half-arguments-and-returns -ffp-contract=fast -S -emit-llvm -o - %s \
+// RUN: -fallow-half-arguments-and-returns -S -emit-llvm -o - %s \
// RUN: | opt -S -mem2reg \
// RUN: | FileCheck %s
diff --git a/test/CodeGen/address-space.c b/test/CodeGen/address-space.c
index 61deb2625336..5d57d5b6ebe5 100644
--- a/test/CodeGen/address-space.c
+++ b/test/CodeGen/address-space.c
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm < %s | FileCheck -check-prefixes=CHECK,GIZ %s
+// RUN: %clang_cc1 -triple amdgcn -emit-llvm < %s | FileCheck -check-prefixes=CHECK,PIZ %s
+// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHeCK,GIZ %s
// CHECK: @foo = common addrspace(1) global
int foo __attribute__((address_space(1)));
@@ -6,6 +8,9 @@ int foo __attribute__((address_space(1)));
// CHECK: @ban = common addrspace(1) global
int ban[10] __attribute__((address_space(1)));
+// CHECK: @a = common global
+int a __attribute__((address_space(0)));
+
// CHECK-LABEL: define i32 @test1()
// CHECK: load i32, i32 addrspace(1)* @foo
int test1() { return foo; }
@@ -19,9 +24,11 @@ int test2(int i) { return ban[i]; }
__attribute__((address_space(2))) int *A, *B;
// CHECK-LABEL: define void @test3()
-// CHECK: load i32 addrspace(2)*, i32 addrspace(2)** @B
+// GIZ: load i32 addrspace(2)*, i32 addrspace(2)** @B
+// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* @B
// CHECK: load i32, i32 addrspace(2)*
-// CHECK: load i32 addrspace(2)*, i32 addrspace(2)** @A
+// GIZ: load i32 addrspace(2)*, i32 addrspace(2)** @A
+// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* @A
// CHECK: store i32 {{.*}}, i32 addrspace(2)*
void test3() {
*A = *B;
diff --git a/test/CodeGen/alloc-align-attr.c b/test/CodeGen/alloc-align-attr.c
new file mode 100644
index 000000000000..b7cfcf76d451
--- /dev/null
+++ b/test/CodeGen/alloc-align-attr.c
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s
+
+__INT32_TYPE__*m1(__INT32_TYPE__ i) __attribute__((alloc_align(1)));
+
+// Condition where parameter to m1 is not size_t.
+__INT32_TYPE__ test1(__INT32_TYPE__ a) {
+// CHECK: define i32 @test1
+ return *m1(a);
+// CHECK: call i32* @m1(i32 [[PARAM1:%[^\)]+]])
+// CHECK: [[ALIGNCAST1:%.+]] = sext i32 [[PARAM1]] to i64
+// CHECK: [[ISPOS1:%.+]] = icmp sgt i64 [[ALIGNCAST1]], 0
+// CHECK: [[POSMASK1:%.+]] = sub i64 [[ALIGNCAST1]], 1
+// CHECK: [[MASK1:%.+]] = select i1 [[ISPOS1]], i64 [[POSMASK1]], i64 0
+// CHECK: [[PTRINT1:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR1:%.+]] = and i64 [[PTRINT1]], [[MASK1]]
+// CHECK: [[MASKCOND1:%.+]] = icmp eq i64 [[MASKEDPTR1]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND1]])
+}
+// Condition where test2 param needs casting.
+__INT32_TYPE__ test2(__SIZE_TYPE__ a) {
+// CHECK: define i32 @test2
+ return *m1(a);
+// CHECK: [[CONV2:%.+]] = trunc i64 %{{.+}} to i32
+// CHECK: call i32* @m1(i32 [[CONV2]])
+// CHECK: [[ALIGNCAST2:%.+]] = sext i32 [[CONV2]] to i64
+// CHECK: [[ISPOS2:%.+]] = icmp sgt i64 [[ALIGNCAST2]], 0
+// CHECK: [[POSMASK2:%.+]] = sub i64 [[ALIGNCAST2]], 1
+// CHECK: [[MASK2:%.+]] = select i1 [[ISPOS2]], i64 [[POSMASK2]], i64 0
+// CHECK: [[PTRINT2:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR2:%.+]] = and i64 [[PTRINT2]], [[MASK2]]
+// CHECK: [[MASKCOND2:%.+]] = icmp eq i64 [[MASKEDPTR2]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND2]])
+}
+__INT32_TYPE__ *m2(__SIZE_TYPE__ i) __attribute__((alloc_align(1)));
+
+// test3 param needs casting, but 'm2' is correct.
+__INT32_TYPE__ test3(__INT32_TYPE__ a) {
+// CHECK: define i32 @test3
+ return *m2(a);
+// CHECK: [[CONV3:%.+]] = sext i32 %{{.+}} to i64
+// CHECK: call i32* @m2(i64 [[CONV3]])
+// CHECK: [[ISPOS3:%.+]] = icmp sgt i64 [[CONV3]], 0
+// CHECK: [[POSMASK3:%.+]] = sub i64 [[CONV3]], 1
+// CHECK: [[MASK3:%.+]] = select i1 [[ISPOS3]], i64 [[POSMASK3]], i64 0
+// CHECK: [[PTRINT3:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR3:%.+]] = and i64 [[PTRINT3]], [[MASK3]]
+// CHECK: [[MASKCOND3:%.+]] = icmp eq i64 [[MASKEDPTR3]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND3]])
+}
+
+// Every type matches, canonical example.
+__INT32_TYPE__ test4(__SIZE_TYPE__ a) {
+// CHECK: define i32 @test4
+ return *m2(a);
+// CHECK: call i32* @m2(i64 [[PARAM4:%[^\)]+]])
+// CHECK: [[ISPOS4:%.+]] = icmp sgt i64 [[PARAM4]], 0
+// CHECK: [[POSMASK4:%.+]] = sub i64 [[PARAM4]], 1
+// CHECK: [[MASK4:%.+]] = select i1 [[ISPOS4]], i64 [[POSMASK4]], i64 0
+// CHECK: [[PTRINT4:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR4:%.+]] = and i64 [[PTRINT4]], [[MASK4]]
+// CHECK: [[MASKCOND4:%.+]] = icmp eq i64 [[MASKEDPTR4]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND4]])
+}
+
+
+struct Empty {};
+struct MultiArgs { __INT64_TYPE__ a, b;};
+// Struct parameter doesn't take up an IR parameter, 'i' takes up 2.
+// Truncation to i64 is permissible, since alignments of greater than 2^64 are insane.
+__INT32_TYPE__ *m3(struct Empty s, __int128_t i) __attribute__((alloc_align(2)));
+__INT32_TYPE__ test5(__int128_t a) {
+// CHECK: define i32 @test5
+ struct Empty e;
+ return *m3(e, a);
+// CHECK: call i32* @m3(i64 %{{.*}}, i64 %{{.*}})
+// CHECK: [[ALIGNCAST5:%.+]] = trunc i128 %{{.*}} to i64
+// CHECK: [[ISPOS5:%.+]] = icmp sgt i64 [[ALIGNCAST5]], 0
+// CHECK: [[POSMASK5:%.+]] = sub i64 [[ALIGNCAST5]], 1
+// CHECK: [[MASK5:%.+]] = select i1 [[ISPOS5]], i64 [[POSMASK5]], i64 0
+// CHECK: [[PTRINT5:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR5:%.+]] = and i64 [[PTRINT5]], [[MASK5]]
+// CHECK: [[MASKCOND5:%.+]] = icmp eq i64 [[MASKEDPTR5]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND5]])
+}
+// Struct parameter takes up 2 parameters, 'i' takes up 2.
+__INT32_TYPE__ *m4(struct MultiArgs s, __int128_t i) __attribute__((alloc_align(2)));
+__INT32_TYPE__ test6(__int128_t a) {
+// CHECK: define i32 @test6
+ struct MultiArgs e;
+ return *m4(e, a);
+// CHECK: call i32* @m4(i64 %{{.*}}, i64 %{{.*}}, i64 %{{.*}})
+// CHECK: [[ALIGNCAST6:%.+]] = trunc i128 %{{.*}} to i64
+// CHECK: [[ISPOS6:%.+]] = icmp sgt i64 [[ALIGNCAST6]], 0
+// CHECK: [[POSMASK6:%.+]] = sub i64 [[ALIGNCAST6]], 1
+// CHECK: [[MASK6:%.+]] = select i1 [[ISPOS6]], i64 [[POSMASK6]], i64 0
+// CHECK: [[PTRINT6:%.+]] = ptrtoint
+// CHECK: [[MASKEDPTR6:%.+]] = and i64 [[PTRINT6]], [[MASK6]]
+// CHECK: [[MASKCOND6:%.+]] = icmp eq i64 [[MASKEDPTR6]], 0
+// CHECK: call void @llvm.assume(i1 [[MASKCOND6]])
+}
+
diff --git a/test/CodeGen/alloc-size.c b/test/CodeGen/alloc-size.c
index 1e503f0579c9..1c98b6874da2 100644
--- a/test/CodeGen/alloc-size.c
+++ b/test/CodeGen/alloc-size.c
@@ -231,7 +231,7 @@ void test7() {
void test8() {
// Non-const pointers aren't currently supported.
void *buf = my_calloc(100, 5);
- // CHECK: @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(buf, 0);
// CHECK: @llvm.objectsize
gi = __builtin_object_size(buf, 1);
diff --git a/test/CodeGen/altivec.c b/test/CodeGen/altivec.c
index 29823031b56a..a4d38fa23b75 100644
--- a/test/CodeGen/altivec.c
+++ b/test/CodeGen/altivec.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -faltivec -triple powerpc-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// Check initialization
diff --git a/test/CodeGen/avr-inline-asm-constraints.c b/test/CodeGen/avr-inline-asm-constraints.c
new file mode 100644
index 000000000000..f1bfbac38978
--- /dev/null
+++ b/test/CodeGen/avr-inline-asm-constraints.c
@@ -0,0 +1,124 @@
+// REQUIRES: avr-registered-target
+// RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+int data;
+
+void a() {
+ // CHECK: call void asm sideeffect "add r5, $0", "a"(i16 %0)
+ asm("add r5, %0" :: "a"(data));
+}
+
+void b() {
+ // CHECK: call void asm sideeffect "add r5, $0", "b"(i16 %0)
+ asm("add r5, %0" :: "b"(data));
+}
+
+void d() {
+ // CHECK: call void asm sideeffect "add r5, $0", "d"(i16 %0)
+ asm("add r5, %0" :: "d"(data));
+}
+
+void l() {
+ // CHECK: call void asm sideeffect "add r5, $0", "l"(i16 %0)
+ asm("add r5, %0" :: "l"(data));
+}
+
+void e() {
+ // CHECK: call void asm sideeffect "add r5, $0", "e"(i16 %0)
+ asm("add r5, %0" :: "e"(data));
+}
+
+void q() {
+ // CHECK: call void asm sideeffect "add r5, $0", "q"(i16 %0)
+ asm("add r5, %0" :: "q"(data));
+}
+
+void r() {
+ // CHECK: call void asm sideeffect "add r5, $0", "r"(i16 %0)
+ asm("add r5, %0" :: "r"(data));
+}
+
+void w() {
+ // CHECK: call void asm sideeffect "add r5, $0", "w"(i16 %0)
+ asm("add r5, %0" :: "w"(data));
+}
+
+void t() {
+ // CHECK: call void asm sideeffect "add r5, $0", "t"(i16 %0)
+ asm("add r5, %0" :: "t"(data));
+}
+
+void x() {
+ // CHECK: call void asm sideeffect "add r5, $0", "x"(i16 %0)
+ asm("add r5, %0" :: "x"(data));
+}
+
+void y() {
+ // CHECK: call void asm sideeffect "add r5, $0", "y"(i16 %0)
+ asm("add r5, %0" :: "y"(data));
+}
+
+void z() {
+ // CHECK: call void asm sideeffect "add r5, $0", "z"(i16 %0)
+ asm("add r5, %0" :: "z"(data));
+}
+
+void I() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "I"(i16 50)
+ asm("subi r30, %0" :: "I"(50));
+}
+
+void J() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "J"(i16 -50)
+ asm("subi r30, %0" :: "J"(-50));
+}
+
+void K() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "K"(i16 2)
+ asm("subi r30, %0" :: "K"(2));
+}
+
+void L() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "L"(i16 0)
+ asm("subi r30, %0" :: "L"(0));
+}
+
+void M() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "M"(i16 255)
+ asm("subi r30, %0" :: "M"(255));
+}
+
+void O() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "O"(i16 16)
+ asm("subi r30, %0" :: "O"(16));
+}
+
+void P() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "P"(i16 1)
+ asm("subi r30, %0" :: "P"(1));
+}
+
+void R() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "R"(i16 -3)
+ asm("subi r30, %0" :: "R"(-3));
+}
+
+void G() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "G"(i16 50)
+ asm("subi r30, %0" :: "G"(50));
+}
+
+void Q() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "Q"(i16 50)
+ asm("subi r30, %0" :: "Q"(50));
+}
+
+void ra() {
+ // CHECK: call void asm sideeffect "subi r30, $0", "ra"(i16 50)
+ asm("subi r30, %0" :: "ra"(50));
+}
+
+void ora() {
+ // CHECK: call i16 asm "subi r30, $0", "=ra"()
+ asm("subi r30, %0" : "=ra"(data));
+}
diff --git a/test/CodeGen/avr-unsupported-inline-asm-constraints.c b/test/CodeGen/avr-unsupported-inline-asm-constraints.c
new file mode 100644
index 000000000000..5a875979a983
--- /dev/null
+++ b/test/CodeGen/avr-unsupported-inline-asm-constraints.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple avr-unknown-unknown -verify %s
+
+const unsigned char val = 0;
+
+int foo() {
+ __asm__ volatile("foo %0, 1" : : "fo" (val)); // expected-error {{invalid input constraint 'fo' in asm}}
+ __asm__ volatile("foo %0, 1" : : "Nd" (val)); // expected-error {{invalid input constraint 'Nd' in asm}}
+}
diff --git a/test/CodeGen/avr/attributes/interrupt.c b/test/CodeGen/avr/attributes/interrupt.c
new file mode 100644
index 000000000000..31b7ebb4f03d
--- /dev/null
+++ b/test/CodeGen/avr/attributes/interrupt.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: define void @foo() #0
+__attribute__((interrupt)) void foo(void) { }
+
+// CHECK: attributes #0 = {{{.*interrupt.*}}}
diff --git a/test/CodeGen/avr/attributes/signal.c b/test/CodeGen/avr/attributes/signal.c
new file mode 100644
index 000000000000..82859000060e
--- /dev/null
+++ b/test/CodeGen/avr/attributes/signal.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: define void @foo() #0
+__attribute__((signal)) void foo(void) { }
+
+// CHECK: attributes #0 = {{{.*signal.*}}}
diff --git a/test/CodeGen/avr/target-cpu-defines/atmega328p.c b/test/CodeGen/avr/target-cpu-defines/atmega328p.c
new file mode 100644
index 000000000000..83b0accbb93f
--- /dev/null
+++ b/test/CodeGen/avr/target-cpu-defines/atmega328p.c
@@ -0,0 +1,7 @@
+// REQUIRES: avr-registered-target
+// RUN: %clang_cc1 -E -dM -triple avr-unknown-unknown -target-cpu atmega328p /dev/null | FileCheck -match-full-lines %s
+
+// CHECK: #define AVR 1
+// CHECK: #define __AVR 1
+// CHECK: #define __AVR_ATmega328P__ 1
+// CHECK: #define __AVR__ 1
diff --git a/test/CodeGen/avr/target-cpu-defines/attiny104.c b/test/CodeGen/avr/target-cpu-defines/attiny104.c
new file mode 100644
index 000000000000..7de65bf09ba3
--- /dev/null
+++ b/test/CodeGen/avr/target-cpu-defines/attiny104.c
@@ -0,0 +1,7 @@
+// REQUIRES: avr-registered-target
+// RUN: %clang_cc1 -E -dM -triple avr-unknown-unknown -target-cpu attiny104 /dev/null | FileCheck -match-full-lines %s
+
+// CHECK: #define AVR 1
+// CHECK: #define __AVR 1
+// CHECK: #define __AVR_ATtiny104__ 1
+// CHECK: #define __AVR__ 1
diff --git a/test/CodeGen/avr/target-cpu-defines/common.c b/test/CodeGen/avr/target-cpu-defines/common.c
new file mode 100644
index 000000000000..0b11f5dbdd59
--- /dev/null
+++ b/test/CodeGen/avr/target-cpu-defines/common.c
@@ -0,0 +1,6 @@
+// REQUIRES: avr-registered-target
+// RUN: %clang_cc1 -E -dM -triple avr-unknown-unknown /dev/null | FileCheck -match-full-lines %s
+
+// CHECK: #define AVR 1
+// CHECK: #define __AVR 1
+// CHECK: #define __AVR__ 1
diff --git a/test/CodeGen/avx-builtins.c b/test/CodeGen/avx-builtins.c
index 6a9f7c050b32..483266408179 100644
--- a/test/CodeGen/avx-builtins.c
+++ b/test/CodeGen/avx-builtins.c
@@ -346,19 +346,19 @@ long long test_mm256_extract_epi64(__m256i A) {
__m128d test_mm256_extractf128_pd(__m256d A) {
// CHECK-LABEL: test_mm256_extractf128_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <2 x i32> <i32 2, i32 3>
return _mm256_extractf128_pd(A, 1);
}
__m128 test_mm256_extractf128_ps(__m256 A) {
// CHECK-LABEL: test_mm256_extractf128_ps
- // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
return _mm256_extractf128_ps(A, 1);
}
__m128i test_mm256_extractf128_si256(__m256i A) {
// CHECK-LABEL: test_mm256_extractf128_si256
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <2 x i32> <i32 2, i32 3>
return _mm256_extractf128_si256(A, 1);
}
@@ -647,32 +647,32 @@ __m256 test_mm256_or_ps(__m256 A, __m256 B) {
__m128d test_mm_permute_pd(__m128d A) {
// CHECK-LABEL: test_mm_permute_pd
- // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <2 x i32> <i32 1, i32 0>
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> zeroinitializer, <2 x i32> <i32 1, i32 0>
return _mm_permute_pd(A, 1);
}
__m256d test_mm256_permute_pd(__m256d A) {
// CHECK-LABEL: test_mm256_permute_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
return _mm256_permute_pd(A, 5);
}
__m128 test_mm_permute_ps(__m128 A) {
// CHECK-LABEL: test_mm_permute_ps
- // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
return _mm_permute_ps(A, 0x1b);
}
// Test case for PR12401
__m128 test2_mm_permute_ps(__m128 a) {
// CHECK-LABEL: test2_mm_permute_ps
- // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <4 x i32> <i32 2, i32 1, i32 2, i32 3>
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <4 x i32> <i32 2, i32 1, i32 2, i32 3>
return _mm_permute_ps(a, 0xe6);
}
__m256 test_mm256_permute_ps(__m256 A) {
// CHECK-LABEL: test_mm256_permute_ps
- // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> undef, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> zeroinitializer, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
return _mm256_permute_ps(A, 0x1b);
}
@@ -1177,7 +1177,7 @@ void test_mm256_storeu2_m128(float* A, float* B, __m256 C) {
// CHECK-LABEL: test_mm256_storeu2_m128
// CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: store <4 x float> %{{.*}}, <4 x float>* %{{.*}}, align 1{{$}}
- // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: store <4 x float> %{{.*}}, <4 x float>* %{{.*}}, align 1{{$}}
_mm256_storeu2_m128(A, B, C);
}
@@ -1186,7 +1186,7 @@ void test_mm256_storeu2_m128d(double* A, double* B, __m256d C) {
// CHECK-LABEL: test_mm256_storeu2_m128d
// CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <2 x i32> <i32 0, i32 1>
// CHECK: store <2 x double> %{{.*}}, <2 x double>* %{{.*}}, align 1{{$}}
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <2 x i32> <i32 2, i32 3>
// CHECK: store <2 x double> %{{.*}}, <2 x double>* %{{.*}}, align 1{{$}}
_mm256_storeu2_m128d(A, B, C);
}
@@ -1195,7 +1195,7 @@ void test_mm256_storeu2_m128i(__m128i* A, __m128i* B, __m256i C) {
// CHECK-LABEL: test_mm256_storeu2_m128i
// CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <2 x i32> <i32 0, i32 1>
// CHECK: store <2 x i64> %{{.*}}, <2 x i64>* %{{.*}}, align 1{{$}}
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <2 x i32> <i32 2, i32 3>
// CHECK: store <2 x i64> %{{.*}}, <2 x i64>* %{{.*}}, align 1{{$}}
_mm256_storeu2_m128i(A, B, C);
}
@@ -1322,19 +1322,19 @@ int test_mm256_testz_si256(__m256 A, __m256 B) {
__m256 test_mm256_undefined_ps() {
// CHECK-LABEL: @test_mm256_undefined_ps
- // CHECK: ret <8 x float> undef
+ // CHECK: ret <8 x float> zeroinitializer
return _mm256_undefined_ps();
}
__m256d test_mm256_undefined_pd() {
// CHECK-LABEL: @test_mm256_undefined_pd
- // CHECK: ret <4 x double> undef
+ // CHECK: ret <4 x double> zeroinitializer
return _mm256_undefined_pd();
}
__m256i test_mm256_undefined_si256() {
// CHECK-LABEL: @test_mm256_undefined_si256
- // CHECK: ret <4 x i64> undef
+ // CHECK: ret <4 x i64> zeroinitializer
return _mm256_undefined_si256();
}
diff --git a/test/CodeGen/avx2-builtins.c b/test/CodeGen/avx2-builtins.c
index 4ccf6e6da97b..10f3e715de9b 100644
--- a/test/CodeGen/avx2-builtins.c
+++ b/test/CodeGen/avx2-builtins.c
@@ -368,20 +368,20 @@ __m256i test_mm256_cvtepu32_epi64(__m128i a) {
__m128i test0_mm256_extracti128_si256_0(__m256i a) {
// CHECK-LABEL: test0_mm256_extracti128_si256
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <2 x i32> <i32 0, i32 1>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <2 x i32> <i32 0, i32 1>
return _mm256_extracti128_si256(a, 0);
}
__m128i test1_mm256_extracti128_si256_1(__m256i a) {
// CHECK-LABEL: test1_mm256_extracti128_si256
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <2 x i32> <i32 2, i32 3>
return _mm256_extracti128_si256(a, 1);
}
// Immediate should be truncated to one bit.
__m128i test2_mm256_extracti128_si256(__m256i a) {
// CHECK-LABEL: test2_mm256_extracti128_si256
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <2 x i32> <i32 0, i32 1>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <2 x i32> <i32 0, i32 1>
return _mm256_extracti128_si256(a, 2);
}
@@ -447,7 +447,7 @@ __m256i test_mm256_mask_i32gather_epi32(__m256i a, int const *b, __m256i c, __m2
__m128i test_mm_i32gather_epi64(long long const *b, __m128i c) {
// CHECK-LABEL: test_mm_i32gather_epi64
- // CHECK: call <2 x i64> @llvm.x86.avx2.gather.d.q(<2 x i64> undef, i8* %{{.*}}, <4 x i32> %{{.*}}, <2 x i64> %{{.*}}, i8 2)
+ // CHECK: call <2 x i64> @llvm.x86.avx2.gather.d.q(<2 x i64> zeroinitializer, i8* %{{.*}}, <4 x i32> %{{.*}}, <2 x i64> %{{.*}}, i8 2)
return _mm_i32gather_epi64(b, c, 2);
}
@@ -459,7 +459,7 @@ __m128i test_mm_mask_i32gather_epi64(__m128i a, long long const *b, __m128i c, _
__m256i test_mm256_i32gather_epi64(long long const *b, __m128i c) {
// CHECK-LABEL: test_mm256_i32gather_epi64
- // CHECK: call <4 x i64> @llvm.x86.avx2.gather.d.q.256(<4 x i64> undef, i8* %{{.*}}, <4 x i32> %{{.*}}, <4 x i64> %{{.*}}, i8 2)
+ // CHECK: call <4 x i64> @llvm.x86.avx2.gather.d.q.256(<4 x i64> zeroinitializer, i8* %{{.*}}, <4 x i32> %{{.*}}, <4 x i64> %{{.*}}, i8 2)
return _mm256_i32gather_epi64(b, c, 2);
}
@@ -474,7 +474,7 @@ __m128d test_mm_i32gather_pd(double const *b, __m128i c) {
// CHECK: [[CMP:%.*]] = fcmp oeq <2 x double>
// CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i64>
// CHECK-NEXT: [[BC:%.*]] = bitcast <2 x i64> [[SEXT]] to <2 x double>
- // CHECK: call <2 x double> @llvm.x86.avx2.gather.d.pd(<2 x double> undef, i8* %{{.*}}, <4 x i32> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ // CHECK: call <2 x double> @llvm.x86.avx2.gather.d.pd(<2 x double> zeroinitializer, i8* %{{.*}}, <4 x i32> %{{.*}}, <2 x double> %{{.*}}, i8 2)
return _mm_i32gather_pd(b, c, 2);
}
@@ -489,7 +489,7 @@ __m256d test_mm256_i32gather_pd(double const *b, __m128i c) {
// CHECK: [[CMP:%.*]] = fcmp oeq <4 x double>
// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i64>
// CHECK-NEXT: [[BC:%.*]] = bitcast <4 x i64> [[SEXT]] to <4 x double>
- // CHECK: call <4 x double> @llvm.x86.avx2.gather.d.pd.256(<4 x double> undef, i8* %{{.*}}, <4 x i32> %{{.*}}, <4 x double> %{{.*}}, i8 2)
+ // CHECK: call <4 x double> @llvm.x86.avx2.gather.d.pd.256(<4 x double> zeroinitializer, i8* %{{.*}}, <4 x i32> %{{.*}}, <4 x double> %{{.*}}, i8 2)
return _mm256_i32gather_pd(b, c, 2);
}
@@ -504,7 +504,7 @@ __m128 test_mm_i32gather_ps(float const *b, __m128i c) {
// CHECK: [[CMP:%.*]] = fcmp oeq <4 x float>
// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32>
// CHECK-NEXT: [[BC:%.*]] = bitcast <4 x i32> [[SEXT]] to <4 x float>
- // CHECK: call <4 x float> @llvm.x86.avx2.gather.d.ps(<4 x float> undef, i8* %{{.*}}, <4 x i32> %{{.*}}, <4 x float> %{{.*}}, i8 2)
+ // CHECK: call <4 x float> @llvm.x86.avx2.gather.d.ps(<4 x float> zeroinitializer, i8* %{{.*}}, <4 x i32> %{{.*}}, <4 x float> %{{.*}}, i8 2)
return _mm_i32gather_ps(b, c, 2);
}
@@ -519,7 +519,7 @@ __m256 test_mm256_i32gather_ps(float const *b, __m256i c) {
// CHECK: [[CMP:%.*]] = fcmp oeq <8 x float>
// CHECK-NEXT: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i32>
// CHECK-NEXT: [[BC:%.*]] = bitcast <8 x i32> [[SEXT]] to <8 x float>
- // CHECK: call <8 x float> @llvm.x86.avx2.gather.d.ps.256(<8 x float> undef, i8* %{{.*}}, <8 x i32> %{{.*}}, <8 x float> %{{.*}}, i8 2)
+ // CHECK: call <8 x float> @llvm.x86.avx2.gather.d.ps.256(<8 x float> zeroinitializer, i8* %{{.*}}, <8 x i32> %{{.*}}, <8 x float> %{{.*}}, i8 2)
return _mm256_i32gather_ps(b, c, 2);
}
@@ -555,7 +555,7 @@ __m128i test_mm256_mask_i64gather_epi32(__m128i a, int const *b, __m256i c, __m1
__m128i test_mm_i64gather_epi64(long long const *b, __m128i c) {
// CHECK-LABEL: test_mm_i64gather_epi64
- // CHECK: call <2 x i64> @llvm.x86.avx2.gather.q.q(<2 x i64> undef, i8* %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 2)
+ // CHECK: call <2 x i64> @llvm.x86.avx2.gather.q.q(<2 x i64> zeroinitializer, i8* %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 2)
return _mm_i64gather_epi64(b, c, 2);
}
@@ -567,7 +567,7 @@ __m128i test_mm_mask_i64gather_epi64(__m128i a, long long const *b, __m128i c, _
__m256i test_mm256_i64gather_epi64(long long const *b, __m256i c) {
// CHECK-LABEL: test_mm256_i64gather_epi64
- // CHECK: call <4 x i64> @llvm.x86.avx2.gather.q.q.256(<4 x i64> undef, i8* %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, i8 2)
+ // CHECK: call <4 x i64> @llvm.x86.avx2.gather.q.q.256(<4 x i64> zeroinitializer, i8* %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, i8 2)
return _mm256_i64gather_epi64(b, c, 2);
}
@@ -582,7 +582,7 @@ __m128d test_mm_i64gather_pd(double const *b, __m128i c) {
// CHECK: [[CMP:%.*]] = fcmp oeq <2 x double>
// CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i64>
// CHECK-NEXT: [[BC:%.*]] = bitcast <2 x i64> [[SEXT]] to <2 x double>
- // CHECK: call <2 x double> @llvm.x86.avx2.gather.q.pd(<2 x double> undef, i8* %{{.*}}, <2 x i64> %{{.*}}, <2 x double> %{{.*}}, i8 2)
+ // CHECK: call <2 x double> @llvm.x86.avx2.gather.q.pd(<2 x double> zeroinitializer, i8* %{{.*}}, <2 x i64> %{{.*}}, <2 x double> %{{.*}}, i8 2)
return _mm_i64gather_pd(b, c, 2);
}
@@ -597,7 +597,7 @@ __m256d test_mm256_i64gather_pd(double const *b, __m256i c) {
// CHECK: [[CMP:%.*]] = fcmp oeq <4 x double>
// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i64>
// CHECK-NEXT: [[BC:%.*]] = bitcast <4 x i64> [[SEXT]] to <4 x double>
- // CHECK: call <4 x double> @llvm.x86.avx2.gather.q.pd.256(<4 x double> undef, i8* %{{.*}}, <4 x i64> %{{.*}}, <4 x double> %{{.*}}, i8 2)
+ // CHECK: call <4 x double> @llvm.x86.avx2.gather.q.pd.256(<4 x double> zeroinitializer, i8* %{{.*}}, <4 x i64> %{{.*}}, <4 x double> %{{.*}}, i8 2)
return _mm256_i64gather_pd(b, c, 2);
}
@@ -612,7 +612,7 @@ __m128 test_mm_i64gather_ps(float const *b, __m128i c) {
// CHECK: [[CMP:%.*]] = fcmp oeq <4 x float>
// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32>
// CHECK-NEXT: [[BC:%.*]] = bitcast <4 x i32> [[SEXT]] to <4 x float>
- // CHECK: call <4 x float> @llvm.x86.avx2.gather.q.ps(<4 x float> undef, i8* %{{.*}}, <2 x i64> %{{.*}}, <4 x float> %{{.*}}, i8 2)
+ // CHECK: call <4 x float> @llvm.x86.avx2.gather.q.ps(<4 x float> zeroinitializer, i8* %{{.*}}, <2 x i64> %{{.*}}, <4 x float> %{{.*}}, i8 2)
return _mm_i64gather_ps(b, c, 2);
}
@@ -627,7 +627,7 @@ __m128 test_mm256_i64gather_ps(float const *b, __m256i c) {
// CHECK: [[CMP:%.*]] = fcmp oeq <4 x float>
// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32>
// CHECK-NEXT: [[BC:%.*]] = bitcast <4 x i32> [[SEXT]] to <4 x float>
- // CHECK: call <4 x float> @llvm.x86.avx2.gather.q.ps.256(<4 x float> undef, i8* %{{.*}}, <4 x i64> %{{.*}}, <4 x float> %{{.*}}, i8 2)
+ // CHECK: call <4 x float> @llvm.x86.avx2.gather.q.ps.256(<4 x float> zeroinitializer, i8* %{{.*}}, <4 x i64> %{{.*}}, <4 x float> %{{.*}}, i8 2)
return _mm256_i64gather_ps(b, c, 2);
}
@@ -895,13 +895,13 @@ __m256i test_mm256_permute2x128_si256(__m256i a, __m256i b) {
__m256i test_mm256_permute4x64_epi64(__m256i a) {
// CHECK-LABEL: test_mm256_permute4x64_epi64
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <4 x i32> <i32 3, i32 0, i32 2, i32 0>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <4 x i32> <i32 3, i32 0, i32 2, i32 0>
return _mm256_permute4x64_epi64(a, 35);
}
__m256d test_mm256_permute4x64_pd(__m256d a) {
// CHECK-LABEL: test_mm256_permute4x64_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <4 x i32> <i32 1, i32 2, i32 1, i32 0>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 1, i32 2, i32 1, i32 0>
return _mm256_permute4x64_pd(a, 25);
}
@@ -1117,7 +1117,7 @@ __m256i test_mm256_srlv_epi64(__m256i a, __m256i b) {
__m256i test_mm256_stream_load_si256(__m256i const *a) {
// CHECK-LABEL: test_mm256_stream_load_si256
- // CHECK: call <4 x i64> @llvm.x86.avx2.movntdqa(i8* %{{.*}})
+ // CHECK: load <4 x i64>, <4 x i64>* %{{.*}}, align 32, !nontemporal
return _mm256_stream_load_si256(a);
}
diff --git a/test/CodeGen/avx512-reduceMinMaxIntrin.c b/test/CodeGen/avx512-reduceMinMaxIntrin.c
index 8249b229c8f5..993e2964a19b 100644
--- a/test/CodeGen/avx512-reduceMinMaxIntrin.c
+++ b/test/CodeGen/avx512-reduceMinMaxIntrin.c
@@ -1,3 +1,5 @@
+// FIXME: We should not be testing with -O2 (ie, a dependency on the entire IR optimizer).
+
// RUN: %clang_cc1 -ffreestanding %s -O2 -triple=x86_64-apple-darwin -target-cpu skylake-avx512 -emit-llvm -o - -Wall -Werror |opt -instnamer -S |FileCheck %s
#include <immintrin.h>
@@ -202,7 +204,7 @@ double test_mm512_mask_reduce_min_pd(__mmask8 __M, __m512d __W){
int test_mm512_reduce_max_epi32(__m512i __W){
// CHECK: %tmp = bitcast <8 x i64> %__W to <16 x i32>
// CHECK: %shuffle1.i = shufflevector <16 x i32> %tmp, <16 x i32> undef, <16 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp1 = icmp sgt <16 x i32> %tmp, %shuffle1.i
+ // CHECK: %tmp1 = icmp slt <16 x i32> %shuffle1.i, %tmp
// CHECK: %tmp2 = select <16 x i1> %tmp1, <16 x i32> %tmp, <16 x i32> %shuffle1.i
// CHECK: %shuffle3.i = shufflevector <16 x i32> %tmp2, <16 x i32> undef, <16 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
// CHECK: %tmp3 = icmp sgt <16 x i32> %tmp2, %shuffle3.i
@@ -223,7 +225,7 @@ int test_mm512_reduce_max_epi32(__m512i __W){
unsigned int test_mm512_reduce_max_epu32(__m512i __W){
// CHECK: %tmp = bitcast <8 x i64> %__W to <16 x i32>
// CHECK: %shuffle1.i = shufflevector <16 x i32> %tmp, <16 x i32> undef, <16 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp1 = icmp ugt <16 x i32> %tmp, %shuffle1.i
+ // CHECK: %tmp1 = icmp ult <16 x i32> %shuffle1.i, %tmp
// CHECK: %tmp2 = select <16 x i1> %tmp1, <16 x i32> %tmp, <16 x i32> %shuffle1.i
// CHECK: %shuffle3.i = shufflevector <16 x i32> %tmp2, <16 x i32> undef, <16 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
// CHECK: %tmp3 = icmp ugt <16 x i32> %tmp2, %shuffle3.i
@@ -258,7 +260,7 @@ float test_mm512_reduce_max_ps(__m512 __W){
int test_mm512_reduce_min_epi32(__m512i __W){
// CHECK: %tmp = bitcast <8 x i64> %__W to <16 x i32>
// CHECK: %shuffle1.i = shufflevector <16 x i32> %tmp, <16 x i32> undef, <16 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp1 = icmp slt <16 x i32> %tmp, %shuffle1.i
+ // CHECK: %tmp1 = icmp sgt <16 x i32> %shuffle1.i, %tmp
// CHECK: %tmp2 = select <16 x i1> %tmp1, <16 x i32> %tmp, <16 x i32> %shuffle1.i
// CHECK: %shuffle3.i = shufflevector <16 x i32> %tmp2, <16 x i32> undef, <16 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
// CHECK: %tmp3 = icmp slt <16 x i32> %tmp2, %shuffle3.i
@@ -279,7 +281,7 @@ int test_mm512_reduce_min_epi32(__m512i __W){
unsigned int test_mm512_reduce_min_epu32(__m512i __W){
// CHECK: %tmp = bitcast <8 x i64> %__W to <16 x i32>
// CHECK: %shuffle1.i = shufflevector <16 x i32> %tmp, <16 x i32> undef, <16 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp1 = icmp ult <16 x i32> %tmp, %shuffle1.i
+ // CHECK: %tmp1 = icmp ugt <16 x i32> %shuffle1.i, %tmp
// CHECK: %tmp2 = select <16 x i1> %tmp1, <16 x i32> %tmp, <16 x i32> %shuffle1.i
// CHECK: %shuffle3.i = shufflevector <16 x i32> %tmp2, <16 x i32> undef, <16 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
// CHECK: %tmp3 = icmp ult <16 x i32> %tmp2, %shuffle3.i
diff --git a/test/CodeGen/avx512bw-builtins.c b/test/CodeGen/avx512bw-builtins.c
index b4dfb5ccb9ec..60d2423e9c34 100644
--- a/test/CodeGen/avx512bw-builtins.c
+++ b/test/CodeGen/avx512bw-builtins.c
@@ -510,62 +510,70 @@ __m512i test_mm512_maskz_abs_epi16(__mmask32 __U, __m512i __A) {
}
__m512i test_mm512_packs_epi32(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_packs_epi32
- // CHECK: @llvm.x86.avx512.mask.packssdw.512
+ // CHECK: @llvm.x86.avx512.packssdw.512
return _mm512_packs_epi32(__A,__B);
}
__m512i test_mm512_maskz_packs_epi32(__mmask32 __M, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_packs_epi32
- // CHECK: @llvm.x86.avx512.mask.packssdw.512
+ // CHECK: @llvm.x86.avx512.packssdw.512
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_maskz_packs_epi32(__M,__A,__B);
}
__m512i test_mm512_mask_packs_epi32(__m512i __W, __mmask32 __M, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_packs_epi32
- // CHECK: @llvm.x86.avx512.mask.packssdw.512
+ // CHECK: @llvm.x86.avx512.packssdw.512
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_mask_packs_epi32(__W,__M,__A,__B);
}
__m512i test_mm512_packs_epi16(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_packs_epi16
- // CHECK: @llvm.x86.avx512.mask.packsswb.512
+ // CHECK: @llvm.x86.avx512.packsswb.512
return _mm512_packs_epi16(__A,__B);
}
__m512i test_mm512_mask_packs_epi16(__m512i __W, __mmask64 __M, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_packs_epi16
- // CHECK: @llvm.x86.avx512.mask.packsswb.512
+ // CHECK: @llvm.x86.avx512.packsswb.512
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_mask_packs_epi16(__W,__M,__A,__B);
}
__m512i test_mm512_maskz_packs_epi16(__mmask64 __M, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_packs_epi16
- // CHECK: @llvm.x86.avx512.mask.packsswb.512
+ // CHECK: @llvm.x86.avx512.packsswb.512
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_maskz_packs_epi16(__M,__A,__B);
}
__m512i test_mm512_packus_epi32(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_packus_epi32
- // CHECK: @llvm.x86.avx512.mask.packusdw.512
+ // CHECK: @llvm.x86.avx512.packusdw.512
return _mm512_packus_epi32(__A,__B);
}
__m512i test_mm512_maskz_packus_epi32(__mmask32 __M, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_packus_epi32
- // CHECK: @llvm.x86.avx512.mask.packusdw.512
+ // CHECK: @llvm.x86.avx512.packusdw.512
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_maskz_packus_epi32(__M,__A,__B);
}
__m512i test_mm512_mask_packus_epi32(__m512i __W, __mmask32 __M, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_packus_epi32
- // CHECK: @llvm.x86.avx512.mask.packusdw.512
+ // CHECK: @llvm.x86.avx512.packusdw.512
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_mask_packus_epi32(__W,__M,__A,__B);
}
__m512i test_mm512_packus_epi16(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_packus_epi16
- // CHECK: @llvm.x86.avx512.mask.packuswb.512
+ // CHECK: @llvm.x86.avx512.packuswb.512
return _mm512_packus_epi16(__A,__B);
}
__m512i test_mm512_mask_packus_epi16(__m512i __W, __mmask64 __M, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_packus_epi16
- // CHECK: @llvm.x86.avx512.mask.packuswb.512
+ // CHECK: @llvm.x86.avx512.packuswb.512
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_mask_packus_epi16(__W,__M,__A,__B);
}
__m512i test_mm512_maskz_packus_epi16(__mmask64 __M, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_packus_epi16
- // CHECK: @llvm.x86.avx512.mask.packuswb.512
+ // CHECK: @llvm.x86.avx512.packuswb.512
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_maskz_packus_epi16(__M,__A,__B);
}
__m512i test_mm512_adds_epi8(__m512i __A, __m512i __B) {
@@ -1535,52 +1543,54 @@ __mmask64 test_mm512_movepi8_mask(__m512i __A) {
__m512i test_mm512_movm_epi8(__mmask64 __A) {
// CHECK-LABEL: @test_mm512_movm_epi8
- // CHECK: @llvm.x86.avx512.cvtmask2b.512
+ // CHECK: %{{.*}} = bitcast i64 %{{.*}} to <64 x i1>
+ // CHECK: %vpmovm2.i = sext <64 x i1> %{{.*}} to <64 x i8>
return _mm512_movm_epi8(__A);
}
__m512i test_mm512_movm_epi16(__mmask32 __A) {
// CHECK-LABEL: @test_mm512_movm_epi16
- // CHECK: @llvm.x86.avx512.cvtmask2w.512
+ // CHECK: %{{.*}} = bitcast i32 %{{.*}} to <32 x i1>
+ // CHECK: %vpmovm2.i = sext <32 x i1> %{{.*}} to <32 x i16>
return _mm512_movm_epi16(__A);
}
__m512i test_mm512_broadcastb_epi8(__m128i __A) {
// CHECK-LABEL: @test_mm512_broadcastb_epi8
- // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> undef, <64 x i32> zeroinitializer
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> zeroinitializer, <64 x i32> zeroinitializer
return _mm512_broadcastb_epi8(__A);
}
__m512i test_mm512_mask_broadcastb_epi8(__m512i __O, __mmask64 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_mask_broadcastb_epi8
- // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> undef, <64 x i32> zeroinitializer
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> zeroinitializer, <64 x i32> zeroinitializer
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_mask_broadcastb_epi8(__O, __M, __A);
}
__m512i test_mm512_maskz_broadcastb_epi8(__mmask64 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcastb_epi8
- // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> undef, <64 x i32> zeroinitializer
+ // CHECK: shufflevector <16 x i8> %{{.*}}, <16 x i8> zeroinitializer, <64 x i32> zeroinitializer
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_maskz_broadcastb_epi8(__M, __A);
}
__m512i test_mm512_broadcastw_epi16(__m128i __A) {
// CHECK-LABEL: @test_mm512_broadcastw_epi16
- // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> undef, <32 x i32> zeroinitializer
+ // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> zeroinitializer, <32 x i32> zeroinitializer
return _mm512_broadcastw_epi16(__A);
}
__m512i test_mm512_mask_broadcastw_epi16(__m512i __O, __mmask32 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_mask_broadcastw_epi16
- // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> undef, <32 x i32> zeroinitializer
+ // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> zeroinitializer, <32 x i32> zeroinitializer
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_mask_broadcastw_epi16(__O, __M, __A);
}
__m512i test_mm512_maskz_broadcastw_epi16(__mmask32 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcastw_epi16
- // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> undef, <32 x i32> zeroinitializer
+ // CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> zeroinitializer, <32 x i32> zeroinitializer
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_maskz_broadcastw_epi16(__M, __A);
}
@@ -1669,19 +1679,19 @@ void test_mm512_mask_cvtepi16_storeu_epi8 (void * __P, __mmask32 __M, __m512i __
{
// CHECK-LABEL: @test_mm512_mask_cvtepi16_storeu_epi8
// CHECK: @llvm.x86.avx512.mask.pmov.wb.mem.512
- __builtin_ia32_pmovwb512mem_mask ( __P, __A, __M);
+ _mm512_mask_cvtepi16_storeu_epi8 ( __P, __M, __A);
}
void test_mm512_mask_cvtsepi16_storeu_epi8 (void * __P, __mmask32 __M, __m512i __A)
{
// CHECK-LABEL: @test_mm512_mask_cvtsepi16_storeu_epi8
// CHECK: @llvm.x86.avx512.mask.pmovs.wb.mem.512
- __builtin_ia32_pmovswb512mem_mask ( __P, __A, __M);
+ _mm512_mask_cvtsepi16_storeu_epi8 ( __P, __M, __A);
}
void test_mm512_mask_cvtusepi16_storeu_epi8 (void * __P, __mmask32 __M, __m512i __A)
{
// CHECK-LABEL: @test_mm512_mask_cvtusepi16_storeu_epi8
// CHECK: @llvm.x86.avx512.mask.pmovus.wb.mem.512
- __builtin_ia32_pmovuswb512mem_mask ( __P, __A, __M);
+ _mm512_mask_cvtusepi16_storeu_epi8 ( __P, __M, __A);
}
diff --git a/test/CodeGen/avx512dq-builtins.c b/test/CodeGen/avx512dq-builtins.c
index f57433a3616b..ca8566c5979a 100644
--- a/test/CodeGen/avx512dq-builtins.c
+++ b/test/CodeGen/avx512dq-builtins.c
@@ -929,13 +929,15 @@ __mmask16 test_mm512_movepi32_mask(__m512i __A) {
__m512i test_mm512_movm_epi32(__mmask16 __A) {
// CHECK-LABEL: @test_mm512_movm_epi32
- // CHECK: @llvm.x86.avx512.cvtmask2d.512
+ // CHECK: %{{.*}} = bitcast i16 %{{.*}} to <16 x i1>
+ // CHECK: %vpmovm2.i = sext <16 x i1> %{{.*}} to <16 x i32>
return _mm512_movm_epi32(__A);
}
__m512i test_mm512_movm_epi64(__mmask8 __A) {
// CHECK-LABEL: @test_mm512_movm_epi64
- // CHECK: @llvm.x86.avx512.cvtmask2q.512
+ // CHECK: %{{.*}} = bitcast i8 %{{.*}} to <8 x i1>
+ // CHECK: %vpmovm2.i = sext <8 x i1> %{{.*}} to <8 x i64>
return _mm512_movm_epi64(__A);
}
@@ -963,40 +965,44 @@ __m512 test_mm512_maskz_broadcast_f32x2(__mmask16 __M, __m128 __A) {
return _mm512_maskz_broadcast_f32x2(__M, __A);
}
-__m512 test_mm512_broadcast_f32x8(__m256 __A) {
+__m512 test_mm512_broadcast_f32x8(float const* __A) {
// CHECK-LABEL: @test_mm512_broadcast_f32x8
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x8
- return _mm512_broadcast_f32x8(__A);
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ return _mm512_broadcast_f32x8(_mm256_loadu_ps(__A));
}
-__m512 test_mm512_mask_broadcast_f32x8(__m512 __O, __mmask16 __M, __m256 __A) {
+__m512 test_mm512_mask_broadcast_f32x8(__m512 __O, __mmask16 __M, float const* __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_f32x8
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x8
- return _mm512_mask_broadcast_f32x8(__O, __M, __A);
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
+ return _mm512_mask_broadcast_f32x8(__O, __M, _mm256_loadu_ps(__A));
}
-__m512 test_mm512_maskz_broadcast_f32x8(__mmask16 __M, __m256 __A) {
+__m512 test_mm512_maskz_broadcast_f32x8(__mmask16 __M, float const* __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_f32x8
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x8
- return _mm512_maskz_broadcast_f32x8(__M, __A);
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
+ return _mm512_maskz_broadcast_f32x8(__M, _mm256_loadu_ps(__A));
}
-__m512d test_mm512_broadcast_f64x2(__m128d __A) {
+__m512d test_mm512_broadcast_f64x2(double const* __A) {
// CHECK-LABEL: @test_mm512_broadcast_f64x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x2
- return _mm512_broadcast_f64x2(__A);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ return _mm512_broadcast_f64x2(_mm_loadu_pd(__A));
}
-__m512d test_mm512_mask_broadcast_f64x2(__m512d __O, __mmask8 __M, __m128d __A) {
+__m512d test_mm512_mask_broadcast_f64x2(__m512d __O, __mmask8 __M, double const* __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_f64x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x2
- return _mm512_mask_broadcast_f64x2(__O, __M, __A);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
+ return _mm512_mask_broadcast_f64x2(__O, __M, _mm_loadu_pd(__A));
}
-__m512d test_mm512_maskz_broadcast_f64x2(__mmask8 __M, __m128d __A) {
+__m512d test_mm512_maskz_broadcast_f64x2(__mmask8 __M, double const* __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_f64x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x2
- return _mm512_maskz_broadcast_f64x2(__M, __A);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
+ return _mm512_maskz_broadcast_f64x2(__M, _mm_loadu_pd(__A));
}
__m512i test_mm512_broadcast_i32x2(__m128i __A) {
@@ -1017,77 +1023,82 @@ __m512i test_mm512_maskz_broadcast_i32x2(__mmask16 __M, __m128i __A) {
return _mm512_maskz_broadcast_i32x2(__M, __A);
}
-__m512i test_mm512_broadcast_i32x8(__m256i __A) {
+__m512i test_mm512_broadcast_i32x8(__m256i const* __A) {
// CHECK-LABEL: @test_mm512_broadcast_i32x8
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x8
- return _mm512_broadcast_i32x8(__A);
+ // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ return _mm512_broadcast_i32x8(_mm256_loadu_si256(__A));
}
-__m512i test_mm512_mask_broadcast_i32x8(__m512i __O, __mmask16 __M, __m256i __A) {
+__m512i test_mm512_mask_broadcast_i32x8(__m512i __O, __mmask16 __M, __m256i const* __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_i32x8
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x8
- return _mm512_mask_broadcast_i32x8(__O, __M, __A);
+ // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
+ return _mm512_mask_broadcast_i32x8(__O, __M, _mm256_loadu_si256(__A));
}
-__m512i test_mm512_maskz_broadcast_i32x8(__mmask16 __M, __m256i __A) {
+__m512i test_mm512_maskz_broadcast_i32x8(__mmask16 __M, __m256i const* __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_i32x8
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x8
- return _mm512_maskz_broadcast_i32x8(__M, __A);
+ // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
+ return _mm512_maskz_broadcast_i32x8(__M, _mm256_loadu_si256(__A));
}
-__m512i test_mm512_broadcast_i64x2(__m128i __A) {
+__m512i test_mm512_broadcast_i64x2(__m128i const* __A) {
// CHECK-LABEL: @test_mm512_broadcast_i64x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x2
- return _mm512_broadcast_i64x2(__A);
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ return _mm512_broadcast_i64x2(_mm_loadu_si128(__A));
}
-__m512i test_mm512_mask_broadcast_i64x2(__m512i __O, __mmask8 __M, __m128i __A) {
+__m512i test_mm512_mask_broadcast_i64x2(__m512i __O, __mmask8 __M, __m128i const* __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_i64x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x2
- return _mm512_mask_broadcast_i64x2(__O, __M, __A);
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
+ return _mm512_mask_broadcast_i64x2(__O, __M, _mm_loadu_si128(__A));
}
-__m512i test_mm512_maskz_broadcast_i64x2(__mmask8 __M, __m128i __A) {
+__m512i test_mm512_maskz_broadcast_i64x2(__mmask8 __M, __m128i const* __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_i64x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x2
- return _mm512_maskz_broadcast_i64x2(__M, __A);
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
+ return _mm512_maskz_broadcast_i64x2(__M, _mm_loadu_si128(__A));
}
+
__m256 test_mm512_extractf32x8_ps(__m512 __A) {
// CHECK-LABEL: @test_mm512_extractf32x8_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
return _mm512_extractf32x8_ps(__A, 1);
}
__m256 test_mm512_mask_extractf32x8_ps(__m256 __W, __mmask8 __U, __m512 __A) {
// CHECK-LABEL: @test_mm512_mask_extractf32x8_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: select <8 x i1> %{{.*}}, <8 x float> %{{.*}}, <8 x float> %{{.*}}
return _mm512_mask_extractf32x8_ps(__W, __U, __A, 1);
}
__m256 test_mm512_maskz_extractf32x8_ps(__mmask8 __U, __m512 __A) {
// CHECK-LABEL: @test_mm512_maskz_extractf32x8_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: select <8 x i1> %{{.*}}, <8 x float> %{{.*}}, <8 x float> %{{.*}}
return _mm512_maskz_extractf32x8_ps(__U, __A, 1);
}
__m128d test_mm512_extractf64x2_pd(__m512d __A) {
// CHECK-LABEL: @test_mm512_extractf64x2_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <2 x i32> <i32 6, i32 7>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <2 x i32> <i32 6, i32 7>
return _mm512_extractf64x2_pd(__A, 3);
}
__m128d test_mm512_mask_extractf64x2_pd(__m128d __W, __mmask8 __U, __m512d __A) {
// CHECK-LABEL: @test_mm512_mask_extractf64x2_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <2 x i32> <i32 6, i32 7>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <2 x i32> <i32 6, i32 7>
// CHECK: select <2 x i1> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}
return _mm512_mask_extractf64x2_pd(__W, __U, __A, 3);
}
__m128d test_mm512_maskz_extractf64x2_pd(__mmask8 __U, __m512d __A) {
// CHECK-LABEL: @test_mm512_maskz_extractf64x2_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <2 x i32> <i32 6, i32 7>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <2 x i32> <i32 6, i32 7>
// CHECK: select <2 x i1> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}
return _mm512_maskz_extractf64x2_pd(__U, __A, 3);
}
@@ -1114,20 +1125,20 @@ __m256i test_mm512_maskz_extracti32x8_epi32(__mmask8 __U, __m512i __A) {
__m128i test_mm512_extracti64x2_epi64(__m512i __A) {
// CHECK-LABEL: @test_mm512_extracti64x2_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <2 x i32> <i32 6, i32 7>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <2 x i32> <i32 6, i32 7>
return _mm512_extracti64x2_epi64(__A, 3);
}
__m128i test_mm512_mask_extracti64x2_epi64(__m128i __W, __mmask8 __U, __m512i __A) {
// CHECK-LABEL: @test_mm512_mask_extracti64x2_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <2 x i32> <i32 6, i32 7>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <2 x i32> <i32 6, i32 7>
// CHECK: select <2 x i1> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}}
return _mm512_mask_extracti64x2_epi64(__W, __U, __A, 3);
}
__m128i test_mm512_maskz_extracti64x2_epi64(__mmask8 __U, __m512i __A) {
// CHECK-LABEL: @test_mm512_maskz_extracti64x2_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <2 x i32> <i32 6, i32 7>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <2 x i32> <i32 6, i32 7>
// CHECK: select <2 x i1> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}}
return _mm512_maskz_extracti64x2_epi64(__U, __A, 3);
}
diff --git a/test/CodeGen/avx512f-builtins.c b/test/CodeGen/avx512f-builtins.c
index 760783af1ce0..3ae80141b3b9 100644
--- a/test/CodeGen/avx512f-builtins.c
+++ b/test/CodeGen/avx512f-builtins.c
@@ -1241,20 +1241,20 @@ __mmask8 test_mm512_mask_cmpunord_ps_mask(__mmask8 k, __m512 a, __m512 b) {
__m256d test_mm512_extractf64x4_pd(__m512d a)
{
// CHECK-LABEL: @test_mm512_extractf64x4_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
return _mm512_extractf64x4_pd(a, 1);
}
__m256d test_mm512_mask_extractf64x4_pd(__m256d __W,__mmask8 __U,__m512d __A){
// CHECK-LABEL:@test_mm512_mask_extractf64x4_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: select <4 x i1> %{{.*}}, <4 x double> %{{.*}}, <4 x double> %{{.*}}
return _mm512_mask_extractf64x4_pd( __W, __U, __A, 1);
}
__m256d test_mm512_maskz_extractf64x4_pd(__mmask8 __U,__m512d __A){
// CHECK-LABEL:@test_mm512_maskz_extractf64x4_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: select <4 x i1> %{{.*}}, <4 x double> %{{.*}}, <4 x double> %{{.*}}
return _mm512_maskz_extractf64x4_pd( __U, __A, 1);
}
@@ -1262,20 +1262,20 @@ __m256d test_mm512_maskz_extractf64x4_pd(__mmask8 __U,__m512d __A){
__m128 test_mm512_extractf32x4_ps(__m512 a)
{
// CHECK-LABEL: @test_mm512_extractf32x4_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
return _mm512_extractf32x4_ps(a, 1);
}
__m128 test_mm512_mask_extractf32x4_ps(__m128 __W, __mmask8 __U,__m512d __A){
// CHECK-LABEL:@test_mm512_mask_extractf32x4_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: select <4 x i1> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}
return _mm512_mask_extractf32x4_ps( __W, __U, __A, 1);
}
__m128 test_mm512_maskz_extractf32x4_ps( __mmask8 __U,__m512d __A){
// CHECK-LABEL:@test_mm512_maskz_extractf32x4_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: select <4 x i1> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}
return _mm512_maskz_extractf32x4_ps( __U, __A, 1);
}
@@ -2458,25 +2458,25 @@ __m128d test_mm_maskz_min_sd(__mmask8 __U, __m128d __A, __m128d __B) {
__m512 test_mm512_undefined() {
// CHECK-LABEL: @test_mm512_undefined
- // CHECK: ret <16 x float> undef
+ // CHECK: ret <16 x float> zeroinitializer
return _mm512_undefined();
}
__m512 test_mm512_undefined_ps() {
// CHECK-LABEL: @test_mm512_undefined_ps
- // CHECK: ret <16 x float> undef
+ // CHECK: ret <16 x float> zeroinitializer
return _mm512_undefined_ps();
}
__m512d test_mm512_undefined_pd() {
// CHECK-LABEL: @test_mm512_undefined_pd
- // CHECK: ret <8 x double> undef
+ // CHECK: ret <8 x double> zeroinitializer
return _mm512_undefined_pd();
}
__m512i test_mm512_undefined_epi32() {
// CHECK-LABEL: @test_mm512_undefined_epi32
- // CHECK: ret <8 x i64> undef
+ // CHECK: ret <8 x i64> zeroinitializer
return _mm512_undefined_epi32();
}
@@ -3714,40 +3714,40 @@ __m512i test_mm512_mask2_permutex2var_epi64(__m512i __A, __m512i __I, __mmask8 _
__m512d test_mm512_permute_pd(__m512d __X) {
// CHECK-LABEL: @test_mm512_permute_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 4, i32 4, i32 6, i32 6>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 4, i32 4, i32 6, i32 6>
return _mm512_permute_pd(__X, 2);
}
__m512d test_mm512_mask_permute_pd(__m512d __W, __mmask8 __U, __m512d __X) {
// CHECK-LABEL: @test_mm512_mask_permute_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 4, i32 4, i32 6, i32 6>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 4, i32 4, i32 6, i32 6>
// CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
return _mm512_mask_permute_pd(__W, __U, __X, 2);
}
__m512d test_mm512_maskz_permute_pd(__mmask8 __U, __m512d __X) {
// CHECK-LABEL: @test_mm512_maskz_permute_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 4, i32 4, i32 6, i32 6>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 4, i32 4, i32 6, i32 6>
// CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
return _mm512_maskz_permute_pd(__U, __X, 2);
}
__m512 test_mm512_permute_ps(__m512 __X) {
// CHECK-LABEL: @test_mm512_permute_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <16 x i32> <i32 2, i32 0, i32 0, i32 0, i32 6, i32 4, i32 4, i32 4, i32 10, i32 8, i32 8, i32 8, i32 14, i32 12, i32 12, i32 12>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <16 x i32> <i32 2, i32 0, i32 0, i32 0, i32 6, i32 4, i32 4, i32 4, i32 10, i32 8, i32 8, i32 8, i32 14, i32 12, i32 12, i32 12>
return _mm512_permute_ps(__X, 2);
}
__m512 test_mm512_mask_permute_ps(__m512 __W, __mmask16 __U, __m512 __X) {
// CHECK-LABEL: @test_mm512_mask_permute_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <16 x i32> <i32 2, i32 0, i32 0, i32 0, i32 6, i32 4, i32 4, i32 4, i32 10, i32 8, i32 8, i32 8, i32 14, i32 12, i32 12, i32 12>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <16 x i32> <i32 2, i32 0, i32 0, i32 0, i32 6, i32 4, i32 4, i32 4, i32 10, i32 8, i32 8, i32 8, i32 14, i32 12, i32 12, i32 12>
// CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
return _mm512_mask_permute_ps(__W, __U, __X, 2);
}
__m512 test_mm512_maskz_permute_ps(__mmask16 __U, __m512 __X) {
// CHECK-LABEL: @test_mm512_maskz_permute_ps
- // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> undef, <16 x i32> <i32 2, i32 0, i32 0, i32 0, i32 6, i32 4, i32 4, i32 4, i32 10, i32 8, i32 8, i32 8, i32 14, i32 12, i32 12, i32 12>
+ // CHECK: shufflevector <16 x float> %{{.*}}, <16 x float> zeroinitializer, <16 x i32> <i32 2, i32 0, i32 0, i32 0, i32 6, i32 4, i32 4, i32 4, i32 10, i32 8, i32 8, i32 8, i32 14, i32 12, i32 12, i32 12>
// CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
return _mm512_maskz_permute_ps(__U, __X, 2);
}
@@ -4647,154 +4647,162 @@ __m128 test_mm_maskz_sqrt_round_ss(__mmask8 __U, __m128 __A, __m128 __B){
return _mm_maskz_sqrt_round_ss(__U,__A,__B,_MM_FROUND_CUR_DIRECTION);
}
-__m512 test_mm512_broadcast_f32x4(__m128 __A) {
+__m512 test_mm512_broadcast_f32x4(float const* __A) {
// CHECK-LABEL: @test_mm512_broadcast_f32x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x4
- return _mm512_broadcast_f32x4(__A);
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ return _mm512_broadcast_f32x4(_mm_loadu_ps(__A));
}
-__m512 test_mm512_mask_broadcast_f32x4(__m512 __O, __mmask16 __M, __m128 __A) {
+__m512 test_mm512_mask_broadcast_f32x4(__m512 __O, __mmask16 __M, float const* __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_f32x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x4
- return _mm512_mask_broadcast_f32x4(__O, __M, __A);
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
+ return _mm512_mask_broadcast_f32x4(__O, __M, _mm_loadu_ps(__A));
}
-__m512 test_mm512_maskz_broadcast_f32x4(__mmask16 __M, __m128 __A) {
+__m512 test_mm512_maskz_broadcast_f32x4(__mmask16 __M, float const* __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_f32x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x4
- return _mm512_maskz_broadcast_f32x4(__M, __A);
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
+ return _mm512_maskz_broadcast_f32x4(__M, _mm_loadu_ps(__A));
}
-__m512d test_mm512_broadcast_f64x4(__m256d __A) {
+__m512d test_mm512_broadcast_f64x4(float const* __A) {
// CHECK-LABEL: @test_mm512_broadcast_f64x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x4
- return _mm512_broadcast_f64x4(__A);
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ return _mm512_broadcast_f64x4(_mm256_loadu_ps(__A));
}
-__m512d test_mm512_mask_broadcast_f64x4(__m512d __O, __mmask8 __M, __m256d __A) {
+__m512d test_mm512_mask_broadcast_f64x4(__m512d __O, __mmask8 __M, float const* __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_f64x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x4
- return _mm512_mask_broadcast_f64x4(__O, __M, __A);
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
+ return _mm512_mask_broadcast_f64x4(__O, __M, _mm256_loadu_ps(__A));
}
-__m512d test_mm512_maskz_broadcast_f64x4(__mmask8 __M, __m256d __A) {
+__m512d test_mm512_maskz_broadcast_f64x4(__mmask8 __M, float const* __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_f64x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x4
- return _mm512_maskz_broadcast_f64x4(__M, __A);
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
+ return _mm512_maskz_broadcast_f64x4(__M, _mm256_loadu_ps(__A));
}
-__m512i test_mm512_broadcast_i32x4(__m128i __A) {
+__m512i test_mm512_broadcast_i32x4(__m128i const* __A) {
// CHECK-LABEL: @test_mm512_broadcast_i32x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x4
- return _mm512_broadcast_i32x4(__A);
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ return _mm512_broadcast_i32x4(_mm_loadu_si128(__A));
}
-__m512i test_mm512_mask_broadcast_i32x4(__m512i __O, __mmask16 __M, __m128i __A) {
+__m512i test_mm512_mask_broadcast_i32x4(__m512i __O, __mmask16 __M, __m128i const* __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_i32x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x4
- return _mm512_mask_broadcast_i32x4(__O, __M, __A);
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
+ return _mm512_mask_broadcast_i32x4(__O, __M, _mm_loadu_si128(__A));
}
-__m512i test_mm512_maskz_broadcast_i32x4(__mmask16 __M, __m128i __A) {
+__m512i test_mm512_maskz_broadcast_i32x4(__mmask16 __M, __m128i const* __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_i32x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x4
- return _mm512_maskz_broadcast_i32x4(__M, __A);
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
+ return _mm512_maskz_broadcast_i32x4(__M, _mm_loadu_si128(__A));
}
-__m512i test_mm512_broadcast_i64x4(__m256i __A) {
+__m512i test_mm512_broadcast_i64x4(__m256i const* __A) {
// CHECK-LABEL: @test_mm512_broadcast_i64x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x4
- return _mm512_broadcast_i64x4(__A);
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ return _mm512_broadcast_i64x4(_mm256_loadu_si256(__A));
}
-__m512i test_mm512_mask_broadcast_i64x4(__m512i __O, __mmask8 __M, __m256i __A) {
+__m512i test_mm512_mask_broadcast_i64x4(__m512i __O, __mmask8 __M, __m256i const* __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_i64x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x4
- return _mm512_mask_broadcast_i64x4(__O, __M, __A);
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
+ return _mm512_mask_broadcast_i64x4(__O, __M, _mm256_loadu_si256(__A));
}
-__m512i test_mm512_maskz_broadcast_i64x4(__mmask8 __M, __m256i __A) {
+__m512i test_mm512_maskz_broadcast_i64x4(__mmask8 __M, __m256i const* __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_i64x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x4
- return _mm512_maskz_broadcast_i64x4(__M, __A);
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
+ return _mm512_maskz_broadcast_i64x4(__M, _mm256_loadu_si256(__A));
}
__m512d test_mm512_broadcastsd_pd(__m128d __A) {
// CHECK-LABEL: @test_mm512_broadcastsd_pd
- // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <8 x i32> zeroinitializer
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> zeroinitializer, <8 x i32> zeroinitializer
return _mm512_broadcastsd_pd(__A);
}
__m512d test_mm512_mask_broadcastsd_pd(__m512d __O, __mmask8 __M, __m128d __A) {
// CHECK-LABEL: @test_mm512_mask_broadcastsd_pd
- // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <8 x i32> zeroinitializer
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> zeroinitializer, <8 x i32> zeroinitializer
// CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
return _mm512_mask_broadcastsd_pd(__O, __M, __A);
}
__m512d test_mm512_maskz_broadcastsd_pd(__mmask8 __M, __m128d __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcastsd_pd
- // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <8 x i32> zeroinitializer
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> zeroinitializer, <8 x i32> zeroinitializer
// CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
return _mm512_maskz_broadcastsd_pd(__M, __A);
}
__m512 test_mm512_broadcastss_ps(__m128 __A) {
// CHECK-LABEL: @test_mm512_broadcastss_ps
- // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <16 x i32> zeroinitializer
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <16 x i32> zeroinitializer
return _mm512_broadcastss_ps(__A);
}
__m512 test_mm512_mask_broadcastss_ps(__m512 __O, __mmask16 __M, __m128 __A) {
// CHECK-LABEL: @test_mm512_mask_broadcastss_ps
- // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <16 x i32> zeroinitializer
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <16 x i32> zeroinitializer
// CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
return _mm512_mask_broadcastss_ps(__O, __M, __A);
}
__m512 test_mm512_maskz_broadcastss_ps(__mmask16 __M, __m128 __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcastss_ps
- // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <16 x i32> zeroinitializer
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <16 x i32> zeroinitializer
// CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
return _mm512_maskz_broadcastss_ps(__M, __A);
}
__m512i test_mm512_broadcastd_epi32(__m128i __A) {
// CHECK-LABEL: @test_mm512_broadcastd_epi32
- // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> undef, <16 x i32> zeroinitializer
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <16 x i32> zeroinitializer
return _mm512_broadcastd_epi32(__A);
}
__m512i test_mm512_mask_broadcastd_epi32(__m512i __O, __mmask16 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_mask_broadcastd_epi32
- // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> undef, <16 x i32> zeroinitializer
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <16 x i32> zeroinitializer
// CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
return _mm512_mask_broadcastd_epi32(__O, __M, __A);
}
__m512i test_mm512_maskz_broadcastd_epi32(__mmask16 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcastd_epi32
- // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> undef, <16 x i32> zeroinitializer
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <16 x i32> zeroinitializer
// CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
return _mm512_maskz_broadcastd_epi32(__M, __A);
}
__m512i test_mm512_broadcastq_epi64(__m128i __A) {
// CHECK-LABEL: @test_mm512_broadcastq_epi64
- // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> undef, <8 x i32> zeroinitializer
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> zeroinitializer, <8 x i32> zeroinitializer
return _mm512_broadcastq_epi64(__A);
}
__m512i test_mm512_mask_broadcastq_epi64(__m512i __O, __mmask8 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_mask_broadcastq_epi64
- // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> undef, <8 x i32> zeroinitializer
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> zeroinitializer, <8 x i32> zeroinitializer
// CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
return _mm512_mask_broadcastq_epi64(__O, __M, __A);
}
__m512i test_mm512_maskz_broadcastq_epi64(__mmask8 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcastq_epi64
- // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> undef, <8 x i32> zeroinitializer
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> zeroinitializer, <8 x i32> zeroinitializer
// CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
return _mm512_maskz_broadcastq_epi64(__M, __A);
}
@@ -5181,20 +5189,20 @@ __m128i test_mm512_maskz_extracti32x4_epi32(__mmask8 __U, __m512i __A) {
__m256i test_mm512_extracti64x4_epi64(__m512i __A) {
// CHECK-LABEL: @test_mm512_extracti64x4_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
return _mm512_extracti64x4_epi64(__A, 1);
}
__m256i test_mm512_mask_extracti64x4_epi64(__m256i __W, __mmask8 __U, __m512i __A) {
// CHECK-LABEL: @test_mm512_mask_extracti64x4_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}
return _mm512_mask_extracti64x4_epi64(__W, __U, __A, 1);
}
__m256i test_mm512_maskz_extracti64x4_epi64(__mmask8 __U, __m512i __A) {
// CHECK-LABEL: @test_mm512_maskz_extracti64x4_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}
return _mm512_maskz_extracti64x4_epi64(__U, __A, 1);
}
@@ -6077,40 +6085,40 @@ __m128d test_mm_mask3_fnmsub_round_sd(__m128d __W, __m128d __X, __m128d __Y, __m
__m512d test_mm512_permutex_pd(__m512d __X) {
// CHECK-LABEL: @test_mm512_permutex_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
return _mm512_permutex_pd(__X, 0);
}
__m512d test_mm512_mask_permutex_pd(__m512d __W, __mmask8 __U, __m512d __X) {
// CHECK-LABEL: @test_mm512_mask_permutex_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
// CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
return _mm512_mask_permutex_pd(__W, __U, __X, 0);
}
__m512d test_mm512_maskz_permutex_pd(__mmask8 __U, __m512d __X) {
// CHECK-LABEL: @test_mm512_maskz_permutex_pd
- // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> undef, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
+ // CHECK: shufflevector <8 x double> %{{.*}}, <8 x double> zeroinitializer, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
// CHECK: select <8 x i1> %{{.*}}, <8 x double> %{{.*}}, <8 x double> %{{.*}}
return _mm512_maskz_permutex_pd(__U, __X, 0);
}
__m512i test_mm512_permutex_epi64(__m512i __X) {
// CHECK-LABEL: @test_mm512_permutex_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
return _mm512_permutex_epi64(__X, 0);
}
__m512i test_mm512_mask_permutex_epi64(__m512i __W, __mmask8 __M, __m512i __X) {
// CHECK-LABEL: @test_mm512_mask_permutex_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
// CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
return _mm512_mask_permutex_epi64(__W, __M, __X, 0);
}
__m512i test_mm512_maskz_permutex_epi64(__mmask8 __M, __m512i __X) {
// CHECK-LABEL: @test_mm512_maskz_permutex_epi64
- // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> undef, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
+ // CHECK: shufflevector <8 x i64> %{{.*}}, <8 x i64> zeroinitializer, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 4, i32 4, i32 4>
// CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
return _mm512_maskz_permutex_epi64(__M, __X, 0);
}
@@ -6243,7 +6251,7 @@ void test_mm512_stream_si512(__m512i * __P, __m512i __A) {
__m512i test_mm512_stream_load_si512(void *__P) {
// CHECK-LABEL: @test_mm512_stream_load_si512
- // CHECK: @llvm.x86.avx512.movntdqa
+ // CHECK: load <8 x i64>, <8 x i64>* %{{.*}}, align 64, !nontemporal
return _mm512_stream_load_si512(__P);
}
@@ -7251,6 +7259,18 @@ __m512i test_mm512_maskz_cvtps_epu32 (__mmask16 __U, __m512 __A)
return _mm512_maskz_cvtps_epu32( __U, __A);
}
+double test_mm512_cvtsd_f64(__m512d A) {
+ // CHECK-LABEL: test_mm512_cvtsd_f64
+ // CHECK: extractelement <8 x double> %{{.*}}, i32 0
+ return _mm512_cvtsd_f64(A);
+}
+
+float test_mm512_cvtss_f32(__m512 A) {
+ // CHECK-LABEL: test_mm512_cvtss_f32
+ // CHECK: extractelement <16 x float> %{{.*}}, i32 0
+ return _mm512_cvtss_f32(A);
+}
+
__m512d test_mm512_mask_max_pd (__m512d __W, __mmask8 __U, __m512d __A, __m512d __B)
{
// CHECK-LABEL: @test_mm512_mask_max_pd
@@ -7704,6 +7724,133 @@ __m512i test_mm512_mask_set1_epi32 (__m512i __O, __mmask16 __M, int __A)
return _mm512_mask_set1_epi32 ( __O, __M, __A);
}
+__m512i test_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) {
+
+ //CHECK-LABEL: @test_mm512_set_epi8
+ //CHECK: load i8, i8* %e63.addr, align 1
+ //CHECK: load i8, i8* %e62.addr, align 1
+ //CHECK: load i8, i8* %e61.addr, align 1
+ //CHECK: load i8, i8* %e60.addr, align 1
+ //CHECK: load i8, i8* %e59.addr, align 1
+ //CHECK: load i8, i8* %e58.addr, align 1
+ //CHECK: load i8, i8* %e57.addr, align 1
+ //CHECK: load i8, i8* %e56.addr, align 1
+ //CHECK: load i8, i8* %e55.addr, align 1
+ //CHECK: load i8, i8* %e54.addr, align 1
+ //CHECK: load i8, i8* %e53.addr, align 1
+ //CHECK: load i8, i8* %e52.addr, align 1
+ //CHECK: load i8, i8* %e51.addr, align 1
+ //CHECK: load i8, i8* %e50.addr, align 1
+ //CHECK: load i8, i8* %e49.addr, align 1
+ //CHECK: load i8, i8* %e48.addr, align 1
+ //CHECK: load i8, i8* %e47.addr, align 1
+ //CHECK: load i8, i8* %e46.addr, align 1
+ //CHECK: load i8, i8* %e45.addr, align 1
+ //CHECK: load i8, i8* %e44.addr, align 1
+ //CHECK: load i8, i8* %e43.addr, align 1
+ //CHECK: load i8, i8* %e42.addr, align 1
+ //CHECK: load i8, i8* %e41.addr, align 1
+ //CHECK: load i8, i8* %e40.addr, align 1
+ //CHECK: load i8, i8* %e39.addr, align 1
+ //CHECK: load i8, i8* %e38.addr, align 1
+ //CHECK: load i8, i8* %e37.addr, align 1
+ //CHECK: load i8, i8* %e36.addr, align 1
+ //CHECK: load i8, i8* %e35.addr, align 1
+ //CHECK: load i8, i8* %e34.addr, align 1
+ //CHECK: load i8, i8* %e33.addr, align 1
+ //CHECK: load i8, i8* %e32.addr, align 1
+ //CHECK: load i8, i8* %e31.addr, align 1
+ //CHECK: load i8, i8* %e30.addr, align 1
+ //CHECK: load i8, i8* %e29.addr, align 1
+ //CHECK: load i8, i8* %e28.addr, align 1
+ //CHECK: load i8, i8* %e27.addr, align 1
+ //CHECK: load i8, i8* %e26.addr, align 1
+ //CHECK: load i8, i8* %e25.addr, align 1
+ //CHECK: load i8, i8* %e24.addr, align 1
+ //CHECK: load i8, i8* %e23.addr, align 1
+ //CHECK: load i8, i8* %e22.addr, align 1
+ //CHECK: load i8, i8* %e21.addr, align 1
+ //CHECK: load i8, i8* %e20.addr, align 1
+ //CHECK: load i8, i8* %e19.addr, align 1
+ //CHECK: load i8, i8* %e18.addr, align 1
+ //CHECK: load i8, i8* %e17.addr, align 1
+ //CHECK: load i8, i8* %e16.addr, align 1
+ //CHECK: load i8, i8* %e15.addr, align 1
+ //CHECK: load i8, i8* %e14.addr, align 1
+ //CHECK: load i8, i8* %e13.addr, align 1
+ //CHECK: load i8, i8* %e12.addr, align 1
+ //CHECK: load i8, i8* %e11.addr, align 1
+ //CHECK: load i8, i8* %e10.addr, align 1
+ //CHECK: load i8, i8* %e9.addr, align 1
+ //CHECK: load i8, i8* %e8.addr, align 1
+ //CHECK: load i8, i8* %e7.addr, align 1
+ //CHECK: load i8, i8* %e6.addr, align 1
+ //CHECK: load i8, i8* %e5.addr, align 1
+ //CHECK: load i8, i8* %e4.addr, align 1
+ //CHECK: load i8, i8* %e3.addr, align 1
+ //CHECK: load i8, i8* %e2.addr, align 1
+ //CHECK: load i8, i8* %e1.addr, align 1
+ //CHECK: load i8, i8* %e0.addr, align 1
+ return _mm512_set_epi8(e63, e62, e61, e60, e59, e58, e57, e56, e55, e54,
+ e53, e52, e51, e50, e49, e48,e47, e46, e45, e44, e43, e42, e41, e40,
+ e39, e38, e37, e36, e35, e34, e33, e32,e31, e30, e29, e28, e27, e26,
+ e25, e24, e23, e22, e21, e20, e19, e18, e17, e16, e15, e14, e13, e12,
+ e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0);
+}
+
+__m512i test_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) {
+ //CHECK-LABEL: @test_mm512_set_epi16
+ //CHECK: insertelement{{.*}}i32 0
+ //CHECK: insertelement{{.*}}i32 1
+ //CHECK: insertelement{{.*}}i32 2
+ //CHECK: insertelement{{.*}}i32 3
+ //CHECK: insertelement{{.*}}i32 4
+ //CHECK: insertelement{{.*}}i32 5
+ //CHECK: insertelement{{.*}}i32 6
+ //CHECK: insertelement{{.*}}i32 7
+ //CHECK: insertelement{{.*}}i32 8
+ //CHECK: insertelement{{.*}}i32 9
+ //CHECK: insertelement{{.*}}i32 10
+ //CHECK: insertelement{{.*}}i32 11
+ //CHECK: insertelement{{.*}}i32 12
+ //CHECK: insertelement{{.*}}i32 13
+ //CHECK: insertelement{{.*}}i32 14
+ //CHECK: insertelement{{.*}}i32 15
+ //CHECK: insertelement{{.*}}i32 16
+ //CHECK: insertelement{{.*}}i32 17
+ //CHECK: insertelement{{.*}}i32 18
+ //CHECK: insertelement{{.*}}i32 19
+ //CHECK: insertelement{{.*}}i32 20
+ //CHECK: insertelement{{.*}}i32 21
+ //CHECK: insertelement{{.*}}i32 22
+ //CHECK: insertelement{{.*}}i32 23
+ //CHECK: insertelement{{.*}}i32 24
+ //CHECK: insertelement{{.*}}i32 25
+ //CHECK: insertelement{{.*}}i32 26
+ //CHECK: insertelement{{.*}}i32 27
+ //CHECK: insertelement{{.*}}i32 28
+ //CHECK: insertelement{{.*}}i32 29
+ //CHECK: insertelement{{.*}}i32 30
+ //CHECK: insertelement{{.*}}i32 31
+ return _mm512_set_epi16(e31, e30, e29, e28, e27, e26, e25, e24, e23, e22,
+ e21, e20, e19, e18, e17, e16, e15, e14, e13, e12, e11, e10, e9, e8, e7,
+ e6, e5, e4, e3, e2, e1, e0);
+
+}
__m512i test_mm512_set_epi32 (int __A, int __B, int __C, int __D,
int __E, int __F, int __G, int __H,
int __I, int __J, int __K, int __L,
diff --git a/test/CodeGen/avx512pf-builtins.c b/test/CodeGen/avx512pf-builtins.c
index 19ee083eae2d..b35d90ca6309 100644
--- a/test/CodeGen/avx512pf-builtins.c
+++ b/test/CodeGen/avx512pf-builtins.c
@@ -6,95 +6,95 @@
void test_mm512_mask_prefetch_i32gather_pd(__m256i index, __mmask8 mask, void const *addr, int hint) {
// CHECK-LABEL: @test_mm512_mask_prefetch_i32gather_pd
// CHECK: @llvm.x86.avx512.gatherpf.dpd
- return _mm512_mask_prefetch_i32gather_pd(index, mask, addr, 2, 1);
+ return _mm512_mask_prefetch_i32gather_pd(index, mask, addr, 2, _MM_HINT_T0);
}
void test_mm512_prefetch_i32gather_pd(__m256i index, void const *addr, int hint) {
// CHECK-LABEL: @test_mm512_prefetch_i32gather_pd
// CHECK: @llvm.x86.avx512.gatherpf.dpd
- return _mm512_prefetch_i32gather_pd(index, addr, 2, 1);
+ return _mm512_prefetch_i32gather_pd(index, addr, 2, _MM_HINT_T0);
}
void test_mm512_mask_prefetch_i32gather_ps(__m512i index, __mmask16 mask, void const *addr, int hint) {
// CHECK-LABEL: @test_mm512_mask_prefetch_i32gather_ps
// CHECK: @llvm.x86.avx512.gatherpf.dps
- return _mm512_mask_prefetch_i32gather_ps(index, mask, addr, 2, 1);
+ return _mm512_mask_prefetch_i32gather_ps(index, mask, addr, 2, _MM_HINT_T0);
}
void test_mm512_prefetch_i32gather_ps(__m512i index, void const *addr, int hint) {
// CHECK-LABEL: @test_mm512_prefetch_i32gather_ps
// CHECK: @llvm.x86.avx512.gatherpf.dps
- return _mm512_prefetch_i32gather_ps(index, addr, 2, 1);
+ return _mm512_prefetch_i32gather_ps(index, addr, 2, _MM_HINT_T0);
}
void test_mm512_mask_prefetch_i64gather_pd(__m512i index, __mmask8 mask, void const *addr, int hint) {
// CHECK-LABEL: @test_mm512_mask_prefetch_i64gather_pd
// CHECK: @llvm.x86.avx512.gatherpf.qpd
- return _mm512_mask_prefetch_i64gather_pd(index, mask, addr, 2, 1);
+ return _mm512_mask_prefetch_i64gather_pd(index, mask, addr, 2, _MM_HINT_T0);
}
void test_mm512_prefetch_i64gather_pd(__m512i index, void const *addr, int hint) {
// CHECK-LABEL: @test_mm512_prefetch_i64gather_pd
// CHECK: @llvm.x86.avx512.gatherpf.qpd
- return _mm512_prefetch_i64gather_pd(index, addr, 2, 1);
+ return _mm512_prefetch_i64gather_pd(index, addr, 2, _MM_HINT_T0);
}
void test_mm512_mask_prefetch_i64gather_ps(__m512i index, __mmask8 mask, void const *addr, int hint) {
// CHECK-LABEL: @test_mm512_mask_prefetch_i64gather_ps
// CHECK: @llvm.x86.avx512.gatherpf.qps
- return _mm512_mask_prefetch_i64gather_ps(index, mask, addr, 2, 1);
+ return _mm512_mask_prefetch_i64gather_ps(index, mask, addr, 2, _MM_HINT_T0);
}
void test_mm512_prefetch_i64gather_ps(__m512i index, void const *addr, int hint) {
// CHECK-LABEL: @test_mm512_prefetch_i64gather_ps
// CHECK: @llvm.x86.avx512.gatherpf.qps
- return _mm512_prefetch_i64gather_ps(index, addr, 2, 1);
+ return _mm512_prefetch_i64gather_ps(index, addr, 2, _MM_HINT_T0);
}
void test_mm512_prefetch_i32scatter_pd(void *addr, __m256i index) {
// CHECK-LABEL: @test_mm512_prefetch_i32scatter_pd
// CHECK: @llvm.x86.avx512.scatterpf.dpd.512
- return _mm512_prefetch_i32scatter_pd(addr, index, 1, 2);
+ return _mm512_prefetch_i32scatter_pd(addr, index, 1, _MM_HINT_T1);
}
void test_mm512_mask_prefetch_i32scatter_pd(void *addr, __mmask8 mask, __m256i index) {
// CHECK-LABEL: @test_mm512_mask_prefetch_i32scatter_pd
// CHECK: @llvm.x86.avx512.scatterpf.dpd.512
- return _mm512_mask_prefetch_i32scatter_pd(addr, mask, index, 1, 2);
+ return _mm512_mask_prefetch_i32scatter_pd(addr, mask, index, 1, _MM_HINT_T1);
}
void test_mm512_prefetch_i32scatter_ps(void *addr, __m512i index) {
// CHECK-LABEL: @test_mm512_prefetch_i32scatter_ps
// CHECK: @llvm.x86.avx512.scatterpf.dps.512
- return _mm512_prefetch_i32scatter_ps(addr, index, 1, 2);
+ return _mm512_prefetch_i32scatter_ps(addr, index, 1, _MM_HINT_T1);
}
void test_mm512_mask_prefetch_i32scatter_ps(void *addr, __mmask16 mask, __m512i index) {
// CHECK-LABEL: @test_mm512_mask_prefetch_i32scatter_ps
// CHECK: @llvm.x86.avx512.scatterpf.dps.512
- return _mm512_mask_prefetch_i32scatter_ps(addr, mask, index, 1, 2);
+ return _mm512_mask_prefetch_i32scatter_ps(addr, mask, index, 1, _MM_HINT_T1);
}
void test_mm512_prefetch_i64scatter_pd(void *addr, __m512i index) {
// CHECK-LABEL: @test_mm512_prefetch_i64scatter_pd
// CHECK: @llvm.x86.avx512.scatterpf.qpd.512
- return _mm512_prefetch_i64scatter_pd(addr, index, 1, 2);
+ return _mm512_prefetch_i64scatter_pd(addr, index, 1, _MM_HINT_T1);
}
void test_mm512_mask_prefetch_i64scatter_pd(void *addr, __mmask16 mask, __m512i index) {
// CHECK-LABEL: @test_mm512_mask_prefetch_i64scatter_pd
// CHECK: @llvm.x86.avx512.scatterpf.qpd.512
- return _mm512_mask_prefetch_i64scatter_pd(addr, mask, index, 1, 2);
+ return _mm512_mask_prefetch_i64scatter_pd(addr, mask, index, 1, _MM_HINT_T1);
}
void test_mm512_prefetch_i64scatter_ps(void *addr, __m512i index) {
// CHECK-LABEL: @test_mm512_prefetch_i64scatter_ps
// CHECK: @llvm.x86.avx512.scatterpf.qps.512
- return _mm512_prefetch_i64scatter_ps(addr, index, 1, 2);
+ return _mm512_prefetch_i64scatter_ps(addr, index, 1, _MM_HINT_T1);
}
void test_mm512_mask_prefetch_i64scatter_ps(void *addr, __mmask16 mask, __m512i index) {
// CHECK-LABEL: @test_mm512_mask_prefetch_i64scatter_ps
// CHECK: @llvm.x86.avx512.scatterpf.qps.512
- return _mm512_mask_prefetch_i64scatter_ps(addr, mask, index, 1, 2);
+ return _mm512_mask_prefetch_i64scatter_ps(addr, mask, index, 1, _MM_HINT_T1);
}
diff --git a/test/CodeGen/avx512vl-builtins.c b/test/CodeGen/avx512vl-builtins.c
index fe4ebe12ddd4..c64b7bcec23e 100644
--- a/test/CodeGen/avx512vl-builtins.c
+++ b/test/CodeGen/avx512vl-builtins.c
@@ -5008,56 +5008,56 @@ __m256 test_mm256_maskz_rcp14_ps(__mmask8 __U, __m256 __A) {
__m128d test_mm_mask_permute_pd(__m128d __W, __mmask8 __U, __m128d __X) {
// CHECK-LABEL: @test_mm_mask_permute_pd
- // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <2 x i32> <i32 1, i32 0>
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> zeroinitializer, <2 x i32> <i32 1, i32 0>
// CHECK: select <2 x i1> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}
return _mm_mask_permute_pd(__W, __U, __X, 1);
}
__m128d test_mm_maskz_permute_pd(__mmask8 __U, __m128d __X) {
// CHECK-LABEL: @test_mm_maskz_permute_pd
- // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <2 x i32> <i32 1, i32 0>
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> zeroinitializer, <2 x i32> <i32 1, i32 0>
// CHECK: select <2 x i1> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}
return _mm_maskz_permute_pd(__U, __X, 1);
}
__m256d test_mm256_mask_permute_pd(__m256d __W, __mmask8 __U, __m256d __X) {
// CHECK-LABEL: @test_mm256_mask_permute_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
// CHECK: select <4 x i1> %{{.*}}, <4 x double> %{{.*}}, <4 x double> %{{.*}}
return _mm256_mask_permute_pd(__W, __U, __X, 5);
}
__m256d test_mm256_maskz_permute_pd(__mmask8 __U, __m256d __X) {
// CHECK-LABEL: @test_mm256_maskz_permute_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 1, i32 0, i32 3, i32 2>
// CHECK: select <4 x i1> %{{.*}}, <4 x double> %{{.*}}, <4 x double> %{{.*}}
return _mm256_maskz_permute_pd(__U, __X, 5);
}
__m128 test_mm_mask_permute_ps(__m128 __W, __mmask8 __U, __m128 __X) {
// CHECK-LABEL: @test_mm_mask_permute_ps
- // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
// CHECK: select <4 x i1> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}
return _mm_mask_permute_ps(__W, __U, __X, 0x1b);
}
__m128 test_mm_maskz_permute_ps(__mmask8 __U, __m128 __X) {
// CHECK-LABEL: @test_mm_maskz_permute_ps
- // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
// CHECK: select <4 x i1> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}
return _mm_maskz_permute_ps(__U, __X, 0x1b);
}
__m256 test_mm256_mask_permute_ps(__m256 __W, __mmask8 __U, __m256 __X) {
// CHECK-LABEL: @test_mm256_mask_permute_ps
- // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> undef, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> zeroinitializer, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
// CHECK: select <8 x i1> %{{.*}}, <8 x float> %{{.*}}, <8 x float> %{{.*}}
return _mm256_mask_permute_ps(__W, __U, __X, 0x1b);
}
__m256 test_mm256_maskz_permute_ps(__mmask8 __U, __m256 __X) {
// CHECK-LABEL: @test_mm256_maskz_permute_ps
- // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> undef, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> zeroinitializer, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
// CHECK: select <8 x i1> %{{.*}}, <8 x float> %{{.*}}, <8 x float> %{{.*}}
return _mm256_maskz_permute_ps(__U, __X, 0x1b);
}
@@ -5734,38 +5734,42 @@ __m256 test_mm256_maskz_rsqrt14_ps(__mmask8 __U, __m256 __A) {
__m256 test_mm256_broadcast_f32x4(__m128 __A) {
// CHECK-LABEL: @test_mm256_broadcast_f32x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x4
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
return _mm256_broadcast_f32x4(__A);
}
__m256 test_mm256_mask_broadcast_f32x4(__m256 __O, __mmask8 __M, __m128 __A) {
// CHECK-LABEL: @test_mm256_mask_broadcast_f32x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x4
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x float> %{{.*}}, <8 x float> %{{.*}}
return _mm256_mask_broadcast_f32x4(__O, __M, __A);
}
__m256 test_mm256_maskz_broadcast_f32x4(__mmask8 __M, __m128 __A) {
// CHECK-LABEL: @test_mm256_maskz_broadcast_f32x4
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x4
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x float> %{{.*}}, <8 x float> %{{.*}}
return _mm256_maskz_broadcast_f32x4(__M, __A);
}
-__m256i test_mm256_broadcast_i32x4(__m128i __A) {
+__m256i test_mm256_broadcast_i32x4(__m128i const* __A) {
// CHECK-LABEL: @test_mm256_broadcast_i32x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x4
- return _mm256_broadcast_i32x4(__A);
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ return _mm256_broadcast_i32x4(_mm_loadu_si128(__A));
}
-__m256i test_mm256_mask_broadcast_i32x4(__m256i __O, __mmask8 __M, __m128i __A) {
+__m256i test_mm256_mask_broadcast_i32x4(__m256i __O, __mmask8 __M, __m128i const* __A) {
// CHECK-LABEL: @test_mm256_mask_broadcast_i32x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x4
- return _mm256_mask_broadcast_i32x4(__O, __M, __A);
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> %{{.*}}
+ return _mm256_mask_broadcast_i32x4(__O, __M, _mm_loadu_si128(__A));
}
-__m256i test_mm256_maskz_broadcast_i32x4(__mmask8 __M, __m128i __A) {
+__m256i test_mm256_maskz_broadcast_i32x4(__mmask8 __M, __m128i const* __A) {
// CHECK-LABEL: @test_mm256_maskz_broadcast_i32x4
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x4
- return _mm256_maskz_broadcast_i32x4(__M, __A);
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> %{{.*}}
+ return _mm256_maskz_broadcast_i32x4(__M, _mm_loadu_si128(__A));
}
__m256d test_mm256_mask_broadcastsd_pd(__m256d __O, __mmask8 __M, __m128d __A) {
@@ -6588,20 +6592,20 @@ void test_mm256_mask_cvtepi64_storeu_epi16(void * __P, __mmask8 __M, __m256i __A
__m128 test_mm256_extractf32x4_ps(__m256 __A) {
// CHECK-LABEL: @test_mm256_extractf32x4_ps
- // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
return _mm256_extractf32x4_ps(__A, 1);
}
__m128 test_mm256_mask_extractf32x4_ps(__m128 __W, __mmask8 __U, __m256 __A) {
// CHECK-LABEL: @test_mm256_mask_extractf32x4_ps
- // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: select <4 x i1> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}
return _mm256_mask_extractf32x4_ps(__W, __U, __A, 1);
}
__m128 test_mm256_maskz_extractf32x4_ps(__mmask8 __U, __m256 __A) {
// CHECK-LABEL: @test_mm256_maskz_extractf32x4_ps
- // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> zeroinitializer, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: select <4 x i1> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}
return _mm256_maskz_extractf32x4_ps(__U, __A, 1);
}
@@ -6836,40 +6840,40 @@ __m256i test_mm256_mask_i32gather_epi32(__m256i __v1_old, __mmask8 __mask, __m25
__m256d test_mm256_permutex_pd(__m256d __X) {
// CHECK-LABEL: @test_mm256_permutex_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
return _mm256_permutex_pd(__X, 3);
}
__m256d test_mm256_mask_permutex_pd(__m256d __W, __mmask8 __U, __m256d __X) {
// CHECK-LABEL: @test_mm256_mask_permutex_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <4 x i32> <i32 1, i32 0, i32 0, i32 0>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 1, i32 0, i32 0, i32 0>
// CHECK: select <4 x i1> %{{.*}}, <4 x double> %{{.*}}, <4 x double> %{{.*}}
return _mm256_mask_permutex_pd(__W, __U, __X, 1);
}
__m256d test_mm256_maskz_permutex_pd(__mmask8 __U, __m256d __X) {
// CHECK-LABEL: @test_mm256_maskz_permutex_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <4 x i32> <i32 1, i32 0, i32 0, i32 0>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 1, i32 0, i32 0, i32 0>
// CHECK: select <4 x i1> %{{.*}}, <4 x double> %{{.*}}, <4 x double> %{{.*}}
return _mm256_maskz_permutex_pd(__U, __X, 1);
}
__m256i test_mm256_permutex_epi64(__m256i __X) {
// CHECK-LABEL: @test_mm256_permutex_epi64
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
return _mm256_permutex_epi64(__X, 3);
}
__m256i test_mm256_mask_permutex_epi64(__m256i __W, __mmask8 __M, __m256i __X) {
// CHECK-LABEL: @test_mm256_mask_permutex_epi64
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
// CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}
return _mm256_mask_permutex_epi64(__W, __M, __X, 3);
}
__m256i test_mm256_maskz_permutex_epi64(__mmask8 __M, __m256i __X) {
// CHECK-LABEL: @test_mm256_maskz_permutex_epi64
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
// CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}
return _mm256_maskz_permutex_epi64(__M, __X, 3);
}
diff --git a/test/CodeGen/avx512vlbw-builtins.c b/test/CodeGen/avx512vlbw-builtins.c
index fe363c9ffde5..5a7283608bc3 100644
--- a/test/CodeGen/avx512vlbw-builtins.c
+++ b/test/CodeGen/avx512vlbw-builtins.c
@@ -2521,25 +2521,29 @@ __mmask32 test_mm256_movepi8_mask(__m256i __A) {
__m128i test_mm_movm_epi8(__mmask16 __A) {
// CHECK-LABEL: @test_mm_movm_epi8
- // CHECK: @llvm.x86.avx512.cvtmask2b.128
+ // CHECK: %{{.*}} = bitcast i16 %{{.*}} to <16 x i1>
+ // CHECK: %vpmovm2.i = sext <16 x i1> %{{.*}} to <16 x i8>
return _mm_movm_epi8(__A);
}
__m256i test_mm256_movm_epi8(__mmask32 __A) {
// CHECK-LABEL: @test_mm256_movm_epi8
- // CHECK: @llvm.x86.avx512.cvtmask2b.256
+ // CHECK: %{{.*}} = bitcast i32 %{{.*}} to <32 x i1>
+ // CHECK: %vpmovm2.i = sext <32 x i1> %{{.*}} to <32 x i8>
return _mm256_movm_epi8(__A);
}
__m128i test_mm_movm_epi16(__mmask8 __A) {
// CHECK-LABEL: @test_mm_movm_epi16
- // CHECK: @llvm.x86.avx512.cvtmask2w.128
+ // CHECK: %{{.*}} = bitcast i8 %{{.*}} to <8 x i1>
+ // CHECK: %vpmovm2.i = sext <8 x i1> %{{.*}} to <8 x i16>
return _mm_movm_epi16(__A);
}
__m256i test_mm256_movm_epi16(__mmask16 __A) {
// CHECK-LABEL: @test_mm256_movm_epi16
- // CHECK: @llvm.x86.avx512.cvtmask2w.256
+ // CHECK: %{{.*}} = bitcast i16 %{{.*}} to <16 x i1>
+ // CHECK: %vpmovm2.i = sext <16 x i1> %{{.*}} to <16 x i16>
return _mm256_movm_epi16(__A);
}
diff --git a/test/CodeGen/avx512vldq-builtins.c b/test/CodeGen/avx512vldq-builtins.c
index 6834b6f46b28..b18c811f845b 100644
--- a/test/CodeGen/avx512vldq-builtins.c
+++ b/test/CodeGen/avx512vldq-builtins.c
@@ -865,25 +865,32 @@ __mmask8 test_mm256_movepi32_mask(__m256i __A) {
__m128i test_mm_movm_epi32(__mmask8 __A) {
// CHECK-LABEL: @test_mm_movm_epi32
- // CHECK: @llvm.x86.avx512.cvtmask2d.128
+ // CHECK: %{{.*}} = bitcast i8 %{{.*}} to <8 x i1>
+ // CHECK: %extract.i = shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ // CHECK: %vpmovm2.i = sext <4 x i1> %extract.i to <4 x i32>
return _mm_movm_epi32(__A);
}
__m256i test_mm256_movm_epi32(__mmask8 __A) {
// CHECK-LABEL: @test_mm256_movm_epi32
- // CHECK: @llvm.x86.avx512.cvtmask2d.256
+ // CHECK: %{{.*}} = bitcast i8 %{{.*}} to <8 x i1>
+ // CHECK: %vpmovm2.i = sext <8 x i1> %{{.*}} to <8 x i32>
return _mm256_movm_epi32(__A);
}
__m128i test_mm_movm_epi64(__mmask8 __A) {
// CHECK-LABEL: @test_mm_movm_epi64
- // CHECK: @llvm.x86.avx512.cvtmask2q.128
+ // CHECK: %{{.*}} = bitcast i8 %{{.*}} to <8 x i1>
+ // CHECK: %extract.i = shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <2 x i32> <i32 0, i32 1>
+ // CHECK: %vpmovm2.i = sext <2 x i1> %extract.i to <2 x i64>
return _mm_movm_epi64(__A);
}
__m256i test_mm256_movm_epi64(__mmask8 __A) {
// CHECK-LABEL: @test_mm256_movm_epi64
- // CHECK: @llvm.x86.avx512.cvtmask2q.256
+ // CHECK: %{{.*}} = bitcast i8 %{{.*}} to <8 x i1>
+ // CHECK: %extract.i = shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ // CHECK: %vpmovm2.i = sext <4 x i1> %extract.i to <4 x i64>
return _mm256_movm_epi64(__A);
}
@@ -918,22 +925,24 @@ __m256 test_mm256_maskz_broadcast_f32x2(__mmask8 __M, __m128 __A) {
return _mm256_maskz_broadcast_f32x2(__M, __A);
}
-__m256d test_mm256_broadcast_f64x2(__m128d __A) {
+__m256d test_mm256_broadcast_f64x2(double const* __A) {
// CHECK-LABEL: @test_mm256_broadcast_f64x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x2
- return _mm256_broadcast_f64x2(__A);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+ return _mm256_broadcast_f64x2(_mm_loadu_pd(__A));
}
-__m256d test_mm256_mask_broadcast_f64x2(__m256d __O, __mmask8 __M, __m128d __A) {
+__m256d test_mm256_mask_broadcast_f64x2(__m256d __O, __mmask8 __M, double const* __A) {
// CHECK-LABEL: @test_mm256_mask_broadcast_f64x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x2
- return _mm256_mask_broadcast_f64x2(__O, __M, __A);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x double> %{{.*}}, <4 x double> %{{.*}}
+ return _mm256_mask_broadcast_f64x2(__O, __M, _mm_loadu_pd(__A));
}
-__m256d test_mm256_maskz_broadcast_f64x2(__mmask8 __M, __m128d __A) {
+__m256d test_mm256_maskz_broadcast_f64x2(__mmask8 __M, double const* __A) {
// CHECK-LABEL: @test_mm256_maskz_broadcast_f64x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf64x2
- return _mm256_maskz_broadcast_f64x2(__M, __A);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x double> %{{.*}}, <4 x double> %{{.*}}
+ return _mm256_maskz_broadcast_f64x2(__M, _mm_loadu_pd(__A));
}
__m128i test_mm_broadcast_i32x2(__m128i __A) {
@@ -972,60 +981,62 @@ __m256i test_mm256_maskz_broadcast_i32x2(__mmask8 __M, __m128i __A) {
return _mm256_maskz_broadcast_i32x2(__M, __A);
}
-__m256i test_mm256_broadcast_i64x2(__m128i __A) {
+__m256i test_mm256_broadcast_i64x2(__m128i const* __A) {
// CHECK-LABEL: @test_mm256_broadcast_i64x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x2
- return _mm256_broadcast_i64x2(__A);
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+ return _mm256_broadcast_i64x2(_mm_loadu_si128(__A));
}
-__m256i test_mm256_mask_broadcast_i64x2(__m256i __O, __mmask8 __M, __m128i __A) {
+__m256i test_mm256_mask_broadcast_i64x2(__m256i __O, __mmask8 __M, __m128i const* __A) {
// CHECK-LABEL: @test_mm256_mask_broadcast_i64x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x2
- return _mm256_mask_broadcast_i64x2(__O, __M, __A);
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}
+ return _mm256_mask_broadcast_i64x2(__O, __M, _mm_loadu_si128(__A));
}
-__m256i test_mm256_maskz_broadcast_i64x2(__mmask8 __M, __m128i __A) {
+__m256i test_mm256_maskz_broadcast_i64x2(__mmask8 __M, __m128i const* __A) {
// CHECK-LABEL: @test_mm256_maskz_broadcast_i64x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti64x2
- return _mm256_maskz_broadcast_i64x2(__M, __A);
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}
+ return _mm256_maskz_broadcast_i64x2(__M, _mm_loadu_si128(__A));
}
__m128d test_mm256_extractf64x2_pd(__m256d __A) {
// CHECK-LABEL: @test_mm256_extractf64x2_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <2 x i32> <i32 2, i32 3>
return _mm256_extractf64x2_pd(__A, 1);
}
__m128d test_mm256_mask_extractf64x2_pd(__m128d __W, __mmask8 __U, __m256d __A) {
// CHECK-LABEL: @test_mm256_mask_extractf64x2_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <2 x i32> <i32 2, i32 3>
// CHECK: select <2 x i1> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}
return _mm256_mask_extractf64x2_pd(__W, __U, __A, 1);
}
__m128d test_mm256_maskz_extractf64x2_pd(__mmask8 __U, __m256d __A) {
// CHECK-LABEL: @test_mm256_maskz_extractf64x2_pd
- // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> zeroinitializer, <2 x i32> <i32 2, i32 3>
// CHECK: select <2 x i1> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}
return _mm256_maskz_extractf64x2_pd(__U, __A, 1);
}
__m128i test_mm256_extracti64x2_epi64(__m256i __A) {
// CHECK-LABEL: @test_mm256_extracti64x2_epi64
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <2 x i32> <i32 2, i32 3>
return _mm256_extracti64x2_epi64(__A, 1);
}
__m128i test_mm256_mask_extracti64x2_epi64(__m128i __W, __mmask8 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_mask_extracti64x2_epi64
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <2 x i32> <i32 2, i32 3>
// CHECK: select <2 x i1> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}}
return _mm256_mask_extracti64x2_epi64(__W, __U, __A, 1);
}
__m128i test_mm256_maskz_extracti64x2_epi64(__mmask8 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_maskz_extracti64x2_epi64
- // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> undef, <2 x i32> <i32 2, i32 3>
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> zeroinitializer, <2 x i32> <i32 2, i32 3>
// CHECK: select <2 x i1> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}}
return _mm256_maskz_extracti64x2_epi64(__U, __A, 1);
}
diff --git a/test/CodeGen/blocks.c b/test/CodeGen/blocks.c
index 2a8182691156..911c63e41d34 100644
--- a/test/CodeGen/blocks.c
+++ b/test/CodeGen/blocks.c
@@ -78,3 +78,37 @@ int main() {
// CHECK: [[ONE:%.*]] = bitcast void (...)* [[ZERO]] to void ()*
// CHECK-NEXT: br label [[CE:%.*]]
+// Ensure that we don't emit helper code in copy/dispose routines for variables
+// that are const-captured.
+void testConstCaptureInCopyAndDestroyHelpers() {
+ const int x = 0;
+ __block int i;
+ (^ { i = x; })();
+}
+// CHECK-LABEL: testConstCaptureInCopyAndDestroyHelpers_block_invoke
+
+// CHECK: @__copy_helper_block
+// CHECK: alloca
+// CHECK-NEXT: alloca
+// CHECK-NEXT: store
+// CHECK-NEXT: store
+// CHECK-NEXT: load
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: load
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: getelementptr
+// CHECK-NEXT: getelementptr
+// CHECK-NEXT: load
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: call void @_Block_object_assign
+// CHECK-NEXT: ret
+
+// CHECK: @__destroy_helper_block
+// CHECK: alloca
+// CHECK-NEXT: store
+// CHECK-NEXT: load
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: getelementptr
+// CHECK-NEXT: load
+// CHECK-NEXT: call void @_Block_object_dispose
+// CHECK-NEXT: ret
diff --git a/test/CodeGen/builtin-clflushopt.c b/test/CodeGen/builtin-clflushopt.c
index e98c2aaba573..93861164c4a8 100644
--- a/test/CodeGen/builtin-clflushopt.c
+++ b/test/CodeGen/builtin-clflushopt.c
@@ -3,7 +3,7 @@
#include <immintrin.h>
void test_mm_clflushopt(char * __m) {
- //CHECK-LABLE: @test_mm_clflushopt
+ //CHECK-LABEL: @test_mm_clflushopt
//CHECK: @llvm.x86.clflushopt
_mm_clflushopt(__m);
}
diff --git a/test/CodeGen/builtin-clzero.c b/test/CodeGen/builtin-clzero.c
new file mode 100644
index 000000000000..c9960ced12ec
--- /dev/null
+++ b/test/CodeGen/builtin-clzero.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +clzero -emit-llvm -o - -Wall -Werror | FileCheck %s
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+void test_mm_clzero(void * __m) {
+ //CHECK-LABEL: @test_mm_clzero
+ //CHECK: @llvm.x86.clzero
+ _mm_clzero(__m);
+}
diff --git a/test/CodeGen/builtins-mips-msa-error.c b/test/CodeGen/builtins-mips-msa-error.c
index fcdf6f0c48c8..11750922bb4f 100644
--- a/test/CodeGen/builtins-mips-msa-error.c
+++ b/test/CodeGen/builtins-mips-msa-error.c
@@ -119,7 +119,7 @@ void test(void) {
v4i32_r = __msa_ld_w(&v4i32_a, 512); // expected-error {{argument should be a value from -512 to 511}}
v2i64_r = __msa_ld_d(&v2i64_a, 512); // expected-error {{argument should be a value from -512 to 511}}
- v16i8_r = __msa_ldi_b(512); // expected-error {{argument should be a value from -512 to 511}}
+ v16i8_r = __msa_ldi_b(256); // expected-error {{argument should be a value from -128 to 255}}
v8i16_r = __msa_ldi_h(512); // expected-error {{argument should be a value from -512 to 511}}
v4i32_r = __msa_ldi_w(512); // expected-error {{argument should be a value from -512 to 511}}
v2i64_r = __msa_ldi_d(512); // expected-error {{argument should be a value from -512 to 511}}
@@ -162,11 +162,6 @@ void test(void) {
v8i16_r = __msa_shf_h(v8i16_a, 256); // CHECK: warning: argument should be a value from 0 to 255}}
v4i32_r = __msa_shf_w(v4i32_a, 256); // CHECK: warning: argument should be a value from 0 to 255}}
- v16i8_r = __msa_sld_b(v16i8_r, v16i8_a, 16); // expected-error {{argument should be a value from 0 to 15}}
- v8i16_r = __msa_sld_h(v8i16_r, v8i16_a, 8); // expected-error {{argument should be a value from 0 to 7}}
- v4i32_r = __msa_sld_w(v4i32_r, v4i32_a, 4); // expected-error {{argument should be a value from 0 to 3}}
- v2i64_r = __msa_sld_d(v2i64_r, v2i64_a, 2); // expected-error {{argument should be a value from 0 to 1}}
-
v16i8_r = __msa_sldi_b(v16i8_r, v16i8_a, 16); // expected-error {{argument should be a value from 0 to 15}}
v8i16_r = __msa_sldi_h(v8i16_r, v8i16_a, 8); // expected-error {{argument should be a value from 0 to 7}}
v4i32_r = __msa_sldi_w(v4i32_r, v4i32_a, 4); // expected-error {{argument should be a value from 0 to 3}}
@@ -315,7 +310,7 @@ void test(void) {
v4i32_r = __msa_ld_w(&v4i32_a, -513); // expected-error {{argument should be a value from -512 to 511}}
v2i64_r = __msa_ld_d(&v2i64_a, -513); // expected-error {{argument should be a value from -512 to 511}}
- v16i8_r = __msa_ldi_b(-513); // expected-error {{argument should be a value from -512 to 511}}
+ v16i8_r = __msa_ldi_b(-129); // expected-error {{argument should be a value from -128 to 255}}
v8i16_r = __msa_ldi_h(-513); // expected-error {{argument should be a value from -512 to 511}}
v4i32_r = __msa_ldi_w(-513); // expected-error {{argument should be a value from -512 to 511}}
v2i64_r = __msa_ldi_d(-513); // expected-error {{argument should be a value from -512 to 511}}
@@ -358,11 +353,6 @@ void test(void) {
v8i16_r = __msa_shf_h(v8i16_a, -1); // CHECK: warning: argument should be a value from 0 to 255}}
v4i32_r = __msa_shf_w(v4i32_a, -1); // CHECK: warning: argument should be a value from 0 to 255}}
- v16i8_r = __msa_sld_b(v16i8_r, v16i8_a, -17); // expected-error {{argument should be a value from 0 to 15}}
- v8i16_r = __msa_sld_h(v8i16_r, v8i16_a, -8); // expected-error {{argument should be a value from 0 to 7}}
- v4i32_r = __msa_sld_w(v4i32_r, v4i32_a, -4); // expected-error {{argument should be a value from 0 to 3}}
- v2i64_r = __msa_sld_d(v2i64_r, v2i64_a, -2); // expected-error {{argument should be a value from 0 to 1}}
-
v16i8_r = __msa_sldi_b(v16i8_r, v16i8_a, -17); // expected-error {{argument should be a value from 0 to 15}}
v8i16_r = __msa_sldi_h(v8i16_r, v8i16_a, -8); // expected-error {{argument should be a value from 0 to 7}}
v4i32_r = __msa_sldi_w(v4i32_r, v4i32_a, -4); // expected-error {{argument should be a value from 0 to 3}}
diff --git a/test/CodeGen/builtins-mips-msa.c b/test/CodeGen/builtins-mips-msa.c
index 125679545601..9d09a4209056 100644
--- a/test/CodeGen/builtins-mips-msa.c
+++ b/test/CodeGen/builtins-mips-msa.c
@@ -526,6 +526,8 @@ void test(void) {
v2i64_r = __msa_ld_d(&v2i64_a, 96); // CHECK: call <2 x i64> @llvm.mips.ld.d(
v16i8_r = __msa_ldi_b(3); // CHECK: call <16 x i8> @llvm.mips.ldi.b(
+ v16i8_r = __msa_ldi_b(-128); // CHECK: call <16 x i8> @llvm.mips.ldi.b(
+ v16i8_r = __msa_ldi_b(255); // CHECK: call <16 x i8> @llvm.mips.ldi.b(
v8i16_r = __msa_ldi_h(3); // CHECK: call <8 x i16> @llvm.mips.ldi.h(
v4i32_r = __msa_ldi_w(3); // CHECK: call <4 x i32> @llvm.mips.ldi.w(
v2i64_r = __msa_ldi_d(3); // CHECK: call <2 x i64> @llvm.mips.ldi.d(
@@ -699,6 +701,11 @@ void test(void) {
v4i32_r = __msa_sld_w(v4i32_r, v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sld.w(
v2i64_r = __msa_sld_d(v2i64_r, v2i64_a, 1); // CHECK: call <2 x i64> @llvm.mips.sld.d(
+ v16i8_r = __msa_sld_b(v16i8_r, v16i8_a, 16); // CHECK: call <16 x i8> @llvm.mips.sld.b(
+ v8i16_r = __msa_sld_h(v8i16_r, v8i16_a, 8); // CHECK: call <8 x i16> @llvm.mips.sld.h(
+ v4i32_r = __msa_sld_w(v4i32_r, v4i32_a, 4); // CHECK: call <4 x i32> @llvm.mips.sld.w(
+ v2i64_r = __msa_sld_d(v2i64_r, v2i64_a, 2); // CHECK: call <2 x i64> @llvm.mips.sld.d(
+
v16i8_r = __msa_sldi_b(v16i8_r, v16i8_a, 7); // CHECK: call <16 x i8> @llvm.mips.sldi.b(
v8i16_r = __msa_sldi_h(v8i16_r, v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sldi.h(
v4i32_r = __msa_sldi_w(v4i32_r, v4i32_a, 2); // CHECK: call <4 x i32> @llvm.mips.sldi.w(
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
index 3b75cb49c3fe..99cf3c253879 100644
--- a/test/CodeGen/builtins-ppc-altivec.c
+++ b/test/CodeGen/builtins-ppc-altivec.c
@@ -1,9 +1,9 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -triple powerpc-unknown-unknown -emit-llvm %s \
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc-unknown-unknown -emit-llvm %s \
// RUN: -o - | FileCheck %s
-// RUN: %clang_cc1 -faltivec -triple powerpc64-unknown-unknown -emit-llvm %s \
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc64-unknown-unknown -emit-llvm %s \
// RUN: -o - | FileCheck %s
-// RUN: %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -emit-llvm %s \
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc64le-unknown-unknown -emit-llvm %s \
// RUN: -o - | FileCheck %s -check-prefix=CHECK-LE
// RUN: not %clang_cc1 -triple powerpc64le-unknown-unknown -emit-llvm %s \
// RUN: -ferror-limit 0 -DNO_ALTIVEC -o - 2>&1 \
@@ -3419,28 +3419,40 @@ void test6() {
/* vec_sl */
res_vsc = vec_sl(vsc, vuc);
-// CHECK: shl <16 x i8>
-// CHECK-LE: shl <16 x i8>
+// CHECK: [[UREM:[0-9a-zA-Z%.]+]] = urem <16 x i8> {{[0-9a-zA-Z%.]+}}, <i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8>
+// CHECK: shl <16 x i8> {{[0-9a-zA-Z%.]+}}, [[UREM]]
+// CHECK-LE: [[UREM:[0-9a-zA-Z%.]+]] = urem <16 x i8> {{[0-9a-zA-Z%.]+}}, <i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8>
+// CHECK-LE: shl <16 x i8> {{[0-9a-zA-Z%.]+}}, [[UREM]]
res_vuc = vec_sl(vuc, vuc);
-// CHECK: shl <16 x i8>
-// CHECK-LE: shl <16 x i8>
+// CHECK: [[UREM:[0-9a-zA-Z%.]+]] = urem <16 x i8> {{[0-9a-zA-Z%.]+}}, <i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8>
+// CHECK: shl <16 x i8> {{[0-9a-zA-Z%.]+}}, [[UREM]]
+// CHECK-LE: [[UREM:[0-9a-zA-Z%.]+]] = urem <16 x i8> {{[0-9a-zA-Z%.]+}}, <i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8>
+// CHECK-LE: shl <16 x i8> {{[0-9a-zA-Z%.]+}}, [[UREM]]
res_vs = vec_sl(vs, vus);
-// CHECK: shl <8 x i16>
-// CHECK-LE: shl <8 x i16>
+// CHECK: [[UREM:[0-9a-zA-Z%.]+]] = urem <8 x i16> {{[0-9a-zA-Z%.]+}}, <i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16>
+// CHECK: shl <8 x i16> {{[0-9a-zA-Z%.]+}}, [[UREM]]
+// CHECK-LE: [[UREM:[0-9a-zA-Z%.]+]] = urem <8 x i16> {{[0-9a-zA-Z%.]+}}, <i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16>
+// CHECK-LE: shl <8 x i16> {{[0-9a-zA-Z%.]+}}, [[UREM]]
res_vus = vec_sl(vus, vus);
-// CHECK: shl <8 x i16>
-// CHECK-LE: shl <8 x i16>
+// CHECK: [[UREM:[0-9a-zA-Z%.]+]] = urem <8 x i16> {{[0-9a-zA-Z%.]+}}, <i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16>
+// CHECK: shl <8 x i16> {{[0-9a-zA-Z%.]+}}, [[UREM]]
+// CHECK-LE: [[UREM:[0-9a-zA-Z%.]+]] = urem <8 x i16> {{[0-9a-zA-Z%.]+}}, <i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16>
+// CHECK-LE: shl <8 x i16> {{[0-9a-zA-Z%.]+}}, [[UREM]]
res_vi = vec_sl(vi, vui);
-// CHECK: shl <4 x i32>
-// CHECK-LE: shl <4 x i32>
+// CHECK: [[UREM:[0-9a-zA-Z%.]+]] = urem <4 x i32> {{[0-9a-zA-Z%.]+}}, <i32 32, i32 32, i32 32, i32 32>
+// CHECK: shl <4 x i32> {{[0-9a-zA-Z%.]+}}, [[UREM]]
+// CHECK-LE: [[UREM:[0-9a-zA-Z%.]+]] = urem <4 x i32> {{[0-9a-zA-Z%.]+}}, <i32 32, i32 32, i32 32, i32 32>
+// CHECK-LE: shl <4 x i32> {{[0-9a-zA-Z%.]+}}, [[UREM]]
res_vui = vec_sl(vui, vui);
-// CHECK: shl <4 x i32>
-// CHECK-LE: shl <4 x i32>
+// CHECK: [[UREM:[0-9a-zA-Z%.]+]] = urem <4 x i32> {{[0-9a-zA-Z%.]+}}, <i32 32, i32 32, i32 32, i32 32>
+// CHECK: shl <4 x i32> {{[0-9a-zA-Z%.]+}}, [[UREM]]
+// CHECK-LE: [[UREM:[0-9a-zA-Z%.]+]] = urem <4 x i32> {{[0-9a-zA-Z%.]+}}, <i32 32, i32 32, i32 32, i32 32>
+// CHECK-LE: shl <4 x i32> {{[0-9a-zA-Z%.]+}}, [[UREM]]
res_vsc = vec_vslb(vsc, vuc);
// CHECK: shl <16 x i8>
diff --git a/test/CodeGen/builtins-ppc-crypto-disabled.c b/test/CodeGen/builtins-ppc-crypto-disabled.c
index e6a8a9337aaf..e0b9da0647c0 100644
--- a/test/CodeGen/builtins-ppc-crypto-disabled.c
+++ b/test/CodeGen/builtins-ppc-crypto-disabled.c
@@ -1,13 +1,13 @@
// REQUIRES: powerpc-registered-target
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown \
+// RUN: not %clang_cc1 -target-feature +altivec -triple powerpc64le-unknown-unknown \
// RUN: -target-cpu pwr8 -target-feature -crypto -emit-llvm %s -o - 2>&1 \
// RUN: | FileCheck %s
-// RUN: not %clang_cc1 -faltivec -triple powerpc64-unknown-unknown \
+// RUN: not %clang_cc1 -target-feature +altivec -triple powerpc64-unknown-unknown \
// RUN: -target-cpu pwr8 -target-feature -crypto -emit-llvm %s -o - 2>&1 \
// RUN: | FileCheck %s
-// RUN: not %clang_cc1 -faltivec -triple powerpc64-unknown-unknown \
+// RUN: not %clang_cc1 -target-feature +altivec -triple powerpc64-unknown-unknown \
// RUN: -target-cpu pwr8 -target-feature -power8-vector \
// RUN: -target-feature -crypto -emit-llvm %s -o - 2>&1 \
// RUN: | FileCheck %s -check-prefix=CHECK-P8V
diff --git a/test/CodeGen/builtins-ppc-crypto.c b/test/CodeGen/builtins-ppc-crypto.c
index eaf568b09fb9..04f06f4d67db 100644
--- a/test/CodeGen/builtins-ppc-crypto.c
+++ b/test/CodeGen/builtins-ppc-crypto.c
@@ -1,9 +1,9 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown \
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc64le-unknown-unknown \
// RUN: -target-feature +crypto -target-feature +power8-vector \
// RUN: -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -faltivec -triple powerpc64-unknown-unknown \
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc64-unknown-unknown \
// RUN: -target-feature +crypto -target-feature +power8-vector \
// RUN: -emit-llvm %s -o - | FileCheck %s
#include <altivec.h>
diff --git a/test/CodeGen/builtins-ppc-error.c b/test/CodeGen/builtins-ppc-error.c
index 5860c4f9e77e..e8d2a37a21ed 100644
--- a/test/CodeGen/builtins-ppc-error.c
+++ b/test/CodeGen/builtins-ppc-error.c
@@ -1,10 +1,10 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -target-feature +power9-vector \
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +power9-vector \
// RUN: -triple powerpc64-unknown-unknown -fsyntax-only \
// RUN: -Wall -Werror -verify %s
-// RUN: %clang_cc1 -faltivec -target-feature +power9-vector \
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +power9-vector \
// RUN: -triple powerpc64le-unknown-unknown -fsyntax-only \
// RUN: -Wall -Werror -verify %s
diff --git a/test/CodeGen/builtins-ppc-htm.c b/test/CodeGen/builtins-ppc-htm.c
index 87baa77af81f..d7e7a9148e0f 100644
--- a/test/CodeGen/builtins-ppc-htm.c
+++ b/test/CodeGen/builtins-ppc-htm.c
@@ -1,5 +1,5 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -target-feature +htm -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +htm -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
void test1(long int *r, int code, long int *a, long int *b) {
// CHECK-LABEL: define void @test1
diff --git a/test/CodeGen/builtins-ppc-p8vector.c b/test/CodeGen/builtins-ppc-p8vector.c
index 97a663c2f28f..9f2913847e56 100644
--- a/test/CodeGen/builtins-ppc-p8vector.c
+++ b/test/CodeGen/builtins-ppc-p8vector.c
@@ -1,7 +1,7 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -target-feature +power8-vector -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -faltivec -target-feature +power8-vector -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-LE
-// RUN: not %clang_cc1 -faltivec -target-feature +vsx -triple powerpc64-unknown-unknown -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PPC
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +power8-vector -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +power8-vector -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-LE
+// RUN: not %clang_cc1 -target-feature +altivec -target-feature +vsx -triple powerpc64-unknown-unknown -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PPC
// Added -target-feature +vsx above to avoid errors about "vector double" and to
// generate the correct errors for functions that are only overloaded with VSX
// (vec_cmpge, vec_cmple). Without this option, there is only one overload so
diff --git a/test/CodeGen/builtins-ppc-p9vector.c b/test/CodeGen/builtins-ppc-p9vector.c
index 42316970d8da..f92df86561ad 100644
--- a/test/CodeGen/builtins-ppc-p9vector.c
+++ b/test/CodeGen/builtins-ppc-p9vector.c
@@ -1,9 +1,9 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -target-feature +power9-vector \
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +power9-vector \
// RUN: -triple powerpc64-unknown-unknown -emit-llvm %s \
// RUN: -o - | FileCheck %s -check-prefix=CHECK-BE
-// RUN: %clang_cc1 -faltivec -target-feature +power9-vector \
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +power9-vector \
// RUN: -triple powerpc64le-unknown-unknown -emit-llvm %s \
// RUN: -o - | FileCheck %s
diff --git a/test/CodeGen/builtins-ppc-quadword.c b/test/CodeGen/builtins-ppc-quadword.c
index 3e168c8b1be6..7d014db61323 100644
--- a/test/CodeGen/builtins-ppc-quadword.c
+++ b/test/CodeGen/builtins-ppc-quadword.c
@@ -1,12 +1,12 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -target-feature +power8-vector \
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +power8-vector \
// RUN: -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -faltivec -target-feature +power8-vector \
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +power8-vector \
// RUN: -triple powerpc64le-unknown-unknown -emit-llvm %s -o - \
// RUN: | FileCheck %s -check-prefix=CHECK-LE
-// RUN: not %clang_cc1 -faltivec -triple powerpc-unknown-unknown \
+// RUN: not %clang_cc1 -target-feature +altivec -triple powerpc-unknown-unknown \
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PPC
#include <altivec.h>
diff --git a/test/CodeGen/builtins-ppc-vsx.c b/test/CodeGen/builtins-ppc-vsx.c
index 16c72c404d9c..9e0052630ef7 100644
--- a/test/CodeGen/builtins-ppc-vsx.c
+++ b/test/CodeGen/builtins-ppc-vsx.c
@@ -1,6 +1,6 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -target-feature +vsx -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -faltivec -target-feature +vsx -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-LE
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +vsx -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +vsx -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-LE
#include <altivec.h>
vector bool char vbc = { 0, 1, 0, 1, 0, 1, 0, 1,
diff --git a/test/CodeGen/builtins-wasm.c b/test/CodeGen/builtins-wasm.c
index 135e32976b7d..0c0b87945d42 100644
--- a/test/CodeGen/builtins-wasm.c
+++ b/test/CodeGen/builtins-wasm.c
@@ -9,8 +9,8 @@ __SIZE_TYPE__ f1(void) {
// WEBASSEMBLY64: call {{i.*}} @llvm.wasm.current.memory.i64()
}
-void f2(long delta) {
- __builtin_wasm_grow_memory(delta);
-// WEBASSEMBLY32: call void @llvm.wasm.grow.memory.i32(i32 %{{.*}})
-// WEBASSEMBLY64: call void @llvm.wasm.grow.memory.i64(i64 %{{.*}})
+__SIZE_TYPE__ f2(__SIZE_TYPE__ delta) {
+ return __builtin_wasm_grow_memory(delta);
+// WEBASSEMBLY32: call i32 @llvm.wasm.grow.memory.i32(i32 %{{.*}})
+// WEBASSEMBLY64: call i64 @llvm.wasm.grow.memory.i64(i64 %{{.*}})
}
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
index ec8a8bf868c5..0086f7079dd9 100644
--- a/test/CodeGen/builtins-x86.c
+++ b/test/CodeGen/builtins-x86.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -DUSE_64 -triple x86_64-unknown-unknown -target-feature +fxsr -target-feature +avx -target-feature +xsaveopt -target-feature +xsaves -target-feature +xsavec -target-feature +mwaitx -emit-llvm -o %t %s
-// RUN: %clang_cc1 -DUSE_ALL -triple x86_64-unknown-unknown -target-feature +fxsr -target-feature +avx -target-feature +xsaveopt -target-feature +xsaves -target-feature +xsavec -target-feature +mwaitx -fsyntax-only -o %t %s
+// RUN: %clang_cc1 -DUSE_64 -triple x86_64-unknown-unknown -target-feature +fxsr -target-feature +avx -target-feature +xsaveopt -target-feature +xsaves -target-feature +xsavec -target-feature +mwaitx -target-feature +clzero -emit-llvm -o %t %s
+// RUN: %clang_cc1 -DUSE_ALL -triple x86_64-unknown-unknown -target-feature +fxsr -target-feature +avx -target-feature +xsaveopt -target-feature +xsaves -target-feature +xsavec -target-feature +mwaitx -target-feature +clzero -fsyntax-only -o %t %s
#ifdef USE_ALL
#define USE_3DNOW
@@ -285,6 +285,7 @@ void f0() {
(void) __builtin_ia32_monitorx(tmp_vp, tmp_Ui, tmp_Ui);
(void) __builtin_ia32_mwaitx(tmp_Ui, tmp_Ui, tmp_Ui);
+ (void) __builtin_ia32_clzero(tmp_vp);
tmp_V4f = __builtin_ia32_cvtpi2ps(tmp_V4f, tmp_V2i);
tmp_V2i = __builtin_ia32_cvtps2pi(tmp_V4f);
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index d7a26f8a7d4b..c5f3a79429a0 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift-base,shift-exponent,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift-base,shift-exponent,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | opt -instnamer -S | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-UBSAN
// RUN: %clang_cc1 -fsanitize-trap=alignment,null,object-size,shift-base,shift-exponent,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift-base,shift-exponent,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize=alignment,null,object-size,shift-base,shift-exponent,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -fsanitize-recover=alignment,null,object-size,shift-base,shift-exponent,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute,nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | opt -instnamer -S | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-TRAP
-// RUN: %clang_cc1 -fsanitize=null -fsanitize-recover=null -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-NULL
// RUN: %clang_cc1 -fsanitize=signed-integer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-OVERFLOW
// CHECK-UBSAN: @[[INT:.*]] = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" }
@@ -30,25 +29,20 @@
// CHECK-UBSAN: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 10 {{.*}} @[[FP16]], {{.*}} }
// CHECK-UBSAN: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 10 {{.*}} @{{.*}} }
-// CHECK-NULL: @[[LINE_100:.*]] = private unnamed_addr global {{.*}}, i32 100, i32 5 {{.*}}
-
// PR6805
// CHECK-COMMON-LABEL: @foo
-// CHECK-NULL-LABEL: @foo
void foo() {
union { int i; } u;
- // CHECK-COMMON: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
- // CHECK-COMMON: %[[I8PTR:.*]] = bitcast i32* %[[PTR]] to i8*
- // CHECK-COMMON-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* %[[I8PTR]], i1 false)
- // CHECK-COMMON-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
+ // CHECK-COMMON: %[[I8PTR:.*]] = bitcast i32* %[[PTR:.*]] to i8*
+ // CHECK-COMMON-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* %[[I8PTR]], i1 false, i1 false)
+ // CHECK-COMMON-NEXT: %[[CHECK0:.*]] = icmp uge i64 %[[SIZE]], 4
// CHECK-COMMON: %[[PTRTOINT:.*]] = ptrtoint {{.*}}* %[[PTR]] to i64
// CHECK-COMMON-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRTOINT]], 3
- // CHECK-COMMON-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // CHECK-COMMON-NEXT: %[[CHECK1:.*]] = icmp eq i64 %[[MISALIGN]], 0
- // CHECK-COMMON: %[[CHECK01:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
- // CHECK-COMMON-NEXT: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
+ // CHECK-COMMON: %[[OK:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
// CHECK-UBSAN: br i1 %[[OK]], {{.*}} !prof ![[WEIGHT_MD:.*]], !nosanitize
// CHECK-TRAP: br i1 %[[OK]], {{.*}}
@@ -58,11 +52,6 @@ void foo() {
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW:#[0-9]+]]
// CHECK-TRAP-NEXT: unreachable
-
- // With -fsanitize=null, only perform the null check.
- // CHECK-NULL: %[[NULL:.*]] = icmp ne {{.*}}, null
- // CHECK-NULL: br i1 %[[NULL]]
- // CHECK-NULL: call void @__ubsan_handle_type_mismatch_v1(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %{{.*}})
#line 100
u.i=1;
}
diff --git a/test/CodeGen/cfi-check-fail.c b/test/CodeGen/cfi-check-fail.c
index b850193b54ac..0eb786ab963b 100644
--- a/test/CodeGen/cfi-check-fail.c
+++ b/test/CodeGen/cfi-check-fail.c
@@ -72,3 +72,8 @@ void caller(void (*f)()) {
// CHECK: [[CONT5]]:
// CHECK: ret void
+
+// CHECK: define weak void @__cfi_check(i64, i8*, i8*)
+// CHECK-NOT: }
+// CHECK: call void @llvm.trap()
+// CHECK-NEXT: ret void
diff --git a/test/CodeGen/cleanup-destslot-simple.c b/test/CodeGen/cleanup-destslot-simple.c
index 848a8dc847a9..e7067e7b0485 100644
--- a/test/CodeGen/cleanup-destslot-simple.c
+++ b/test/CodeGen/cleanup-destslot-simple.c
@@ -13,9 +13,9 @@ int test() {
return *p;
// CHECK: [[X:%.*]] = alloca i32
// CHECK: [[P:%.*]] = alloca i32*
-// LIFETIME: call void @llvm.lifetime.start(i64 4, i8* nonnull %{{.*}}){{( #[0-9]+)?}}, !dbg
-// LIFETIME: call void @llvm.lifetime.start(i64 8, i8* nonnull %{{.*}}){{( #[0-9]+)?}}, !dbg
+// LIFETIME: call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %{{.*}}){{( #[0-9]+)?}}, !dbg
+// LIFETIME: call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %{{.*}}){{( #[0-9]+)?}}, !dbg
// CHECK-NOT: store i32 %{{.*}}, i32* %cleanup.dest.slot
-// LIFETIME: call void @llvm.lifetime.end(i64 8, {{.*}}){{( #[0-9]+)?}}, !dbg
-// LIFETIME: call void @llvm.lifetime.end(i64 4, {{.*}}){{( #[0-9]+)?}}, !dbg
+// LIFETIME: call void @llvm.lifetime.end.p0i8(i64 8, {{.*}}){{( #[0-9]+)?}}, !dbg
+// LIFETIME: call void @llvm.lifetime.end.p0i8(i64 4, {{.*}}){{( #[0-9]+)?}}, !dbg
}
diff --git a/test/CodeGen/compound-assign-overflow.c b/test/CodeGen/compound-assign-overflow.c
index f126bb05d53c..92ae249eb9ff 100644
--- a/test/CodeGen/compound-assign-overflow.c
+++ b/test/CodeGen/compound-assign-overflow.c
@@ -25,11 +25,9 @@ void compaddunsigned() {
// CHECK: @__ubsan_handle_add_overflow(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), {{.*}})
}
-int8_t a, b;
-
// CHECK: @compdiv
void compdiv() {
#line 300
- a /= b;
+ x /= x;
// CHECK: @__ubsan_handle_divrem_overflow(i8* bitcast ({{.*}} @[[LINE_300]] to i8*), {{.*}})
}
diff --git a/test/CodeGen/debug-info-macro.c b/test/CodeGen/debug-info-macro.c
new file mode 100644
index 000000000000..889c7ffdbac3
--- /dev/null
+++ b/test/CodeGen/debug-info-macro.c
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=line-tables-only -debug-info-macro %s -o - "-DC1(x)=( x + 5 )" -DA -include %S/Inputs/debug-info-macro.h -UC1 | FileCheck -check-prefixes=CHECK,NO_PCH %s
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -debug-info-macro %s -o - "-DC1(x)=( x + 5 )" -DA -include %S/Inputs/debug-info-macro.h -UC1 | FileCheck -check-prefixes=CHECK,NO_PCH %s
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -debug-info-macro %s -o - "-DC1(x)=( x + 5 )" -DA -include %S/Inputs/debug-info-macro.h -UC1 | FileCheck -check-prefixes=CHECK,NO_PCH %s
+// RUN: %clang_cc1 -emit-llvm -debug-info-macro %s -o - "-DC1(x)=( x + 5 )" -DA -include %S/Inputs/debug-info-macro.h -UC1 | FileCheck -check-prefixes=NO_MACRO %s
+
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -debug-info-macro %S/Inputs/debug-info-macro.h -emit-pch -o %t.pch -DC3
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -debug-info-macro %s -o - -include-pch %t.pch "-DC1(x)=( x + 5 )" -DA -include %S/Inputs/debug-info-macro.h -UC1 | FileCheck -check-prefixes=CHECK,PCH %s
+
+// This test checks that macro Debug info is correctly generated.
+
+// TODO: Check for an following entry once support macros defined in pch files.
+// -PCH: !DIMacro(type: DW_MACINFO_define, name: "C3", value: "1")>
+
+#line 15
+/*Line 15*/ #define D1 1
+/*Line 16*/ #include "Inputs/debug-info-macro.h"
+/*Line 17*/ #undef D1
+/*Line 18*/ #define D2 2
+/*Line 19*/ #include "Inputs/debug-info-macro.h"
+/*Line 20*/ #undef D2
+
+// NO_MACRO-NOT: macros
+// NO_MACRO-NOT: DIMacro
+// NO_MACRO-NOT: DIMacroFile
+
+// CHECK: !DICompileUnit({{.*}} macros: [[Macros:![0-9]+]])
+// CHECK: [[EmptyMD:![0-9]+]] = !{}
+
+// NO_PCH: [[Macros]] = !{[[MainMacroFile:![0-9]+]], [[BuiltinMacro:![0-9]+]], {{.*}}, [[DefineC1:![0-9]+]], [[DefineA:![0-9]+]], [[UndefC1:![0-9]+]]}
+// PCH: [[Macros]] = !{[[MainMacroFile:![0-9]+]], [[DefineC1:![0-9]+]], [[DefineA:![0-9]+]], [[UndefC1:![0-9]+]]}
+
+// CHECK: [[MainMacroFile]] = !DIMacroFile(file: [[MainFile:![0-9]+]], nodes: [[N1:![0-9]+]])
+// CHECK: [[MainFile]] = !DIFile(filename: "{{.*}}debug-info-macro.c"
+// CHECK: [[N1]] = !{[[CommandLineInclude:![0-9]+]], [[DefineD1:![0-9]+]], [[FileInclude1:![0-9]+]], [[UndefD1:![0-9]+]], [[DefineD2:![0-9]+]], [[FileInclude2:![0-9]+]], [[UndefD2:![0-9]+]]}
+
+// CHECK: [[CommandLineInclude]] = !DIMacroFile(file: [[HeaderFile:![0-9]+]], nodes: [[N2:![0-9]+]])
+// CHECK: [[HeaderFile]] = !DIFile(filename: "{{.*}}debug-info-macro.h"
+// CHECK: [[N2]] = !{[[UndefA:![0-9]+]]}
+// CHECK: [[UndefA]] = !DIMacro(type: DW_MACINFO_undef, line: 11, name: "A")
+
+// CHECK: [[DefineD1]] = !DIMacro(type: DW_MACINFO_define, line: 15, name: "D1", value: "1")
+// CHECK: [[FileInclude1]] = !DIMacroFile(line: 16, file: [[HeaderFile]], nodes: [[N3:![0-9]+]])
+// CHECK: [[N3]] = !{[[DefineAx:![0-9]+]], [[UndefA]]}
+// CHECK: [[DefineAx]] = !DIMacro(type: DW_MACINFO_define, line: 3, name: "A(x,y,z)", value: "(x)")
+// CHECK: [[UndefD1]] = !DIMacro(type: DW_MACINFO_undef, line: 17, name: "D1")
+
+// CHECK: [[DefineD2]] = !DIMacro(type: DW_MACINFO_define, line: 18, name: "D2", value: "2")
+// CHECK: [[FileInclude2]] = !DIMacroFile(line: 19, file: [[HeaderFile]], nodes: [[N4:![0-9]+]])
+// CHECK: [[N4]] = !{[[DefineAy:![0-9]+]], [[UndefA]]}
+// CHECK: [[DefineAy]] = !DIMacro(type: DW_MACINFO_define, line: 7, name: "A(x,y,z)", value: "(y)")
+// CHECK: [[UndefD2]] = !DIMacro(type: DW_MACINFO_undef, line: 20, name: "D2")
+
+// NO_PCH: [[BuiltinMacro]] = !DIMacro(type: DW_MACINFO_define, name: "__llvm__", value: "1")
+
+// CHECK: [[DefineC1]] = !DIMacro(type: DW_MACINFO_define, name: "C1(x)", value: "( x + 5 )")
+// CHECK: [[DefineA]] = !DIMacro(type: DW_MACINFO_define, name: "A", value: "1")
+// CHECK: [[UndefC1]] = !DIMacro(type: DW_MACINFO_undef, name: "C1")
diff --git a/test/CodeGen/default-address-space.c b/test/CodeGen/default-address-space.c
new file mode 100644
index 000000000000..07ddf48fac2f
--- /dev/null
+++ b/test/CodeGen/default-address-space.c
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -triple amdgcn -emit-llvm < %s | FileCheck -check-prefixes=PIZ,COM %s
+// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHECK,COM %s
+
+// PIZ-DAG: @foo = common addrspace(4) global i32 0
+// CHECK-DAG: @foo = common global i32 0
+int foo;
+
+// PIZ-DAG: @ban = common addrspace(4) global [10 x i32] zeroinitializer
+// CHECK-DAG: @ban = common global [10 x i32] zeroinitializer
+int ban[10];
+
+// PIZ-DAG: @A = common addrspace(4) global i32 addrspace(4)* null
+// PIZ-DAG: @B = common addrspace(4) global i32 addrspace(4)* null
+// CHECK-DAG: @A = common global i32* null
+// CHECK-DAG: @B = common global i32* null
+int *A;
+int *B;
+
+// COM-LABEL: define i32 @test1()
+// PIZ: load i32, i32 addrspace(4)* @foo
+// CHECK: load i32, i32* @foo
+int test1() { return foo; }
+
+// COM-LABEL: define i32 @test2(i32 %i)
+// PIZ: load i32, i32 addrspace(4)*
+// PIZ-NEXT: ret i32
+// CHECK: load i32, i32*
+// CHECK-NEXT: ret i32
+int test2(int i) { return ban[i]; }
+
+// COM-LABEL: define void @test3()
+// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* @B
+// PIZ: load i32, i32 addrspace(4)*
+// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* @A
+// PIZ: store i32 {{.*}}, i32 addrspace(4)*
+// CHECK: load i32*, i32** @B
+// CHECK: load i32, i32*
+// CHECK: load i32*, i32** @A
+// CHECK: store i32 {{.*}}, i32*
+void test3() {
+ *A = *B;
+}
+
+// PIZ-LABEL: define void @test4(i32 addrspace(4)* %a)
+// PIZ: %[[a_addr:.*]] = alloca i32 addrspace(4)*
+// PIZ: store i32 addrspace(4)* %a, i32 addrspace(4)** %[[a_addr]]
+// PIZ: %[[r0:.*]] = load i32 addrspace(4)*, i32 addrspace(4)** %[[a_addr]]
+// PIZ: %[[arrayidx:.*]] = getelementptr inbounds i32, i32 addrspace(4)* %[[r0]]
+// PIZ: store i32 0, i32 addrspace(4)* %[[arrayidx]]
+// CHECK-LABEL: define void @test4(i32* %a)
+// CHECK: %[[a_addr:.*]] = alloca i32*, align 4, addrspace(5)
+// CHECK: store i32* %a, i32* addrspace(5)* %[[a_addr]]
+// CHECK: %[[r0:.*]] = load i32*, i32* addrspace(5)* %[[a_addr]]
+// CHECK: %[[arrayidx:.*]] = getelementptr inbounds i32, i32* %[[r0]]
+// CHECK: store i32 0, i32* %[[arrayidx]]
+void test4(int *a) {
+ a[0] = 0;
+}
diff --git a/test/CodeGen/fentry.c b/test/CodeGen/fentry.c
new file mode 100644
index 000000000000..b9133184e4d4
--- /dev/null
+++ b/test/CodeGen/fentry.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -pg -mfentry -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -pg -mfentry -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -mfentry -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=NOPG %s
+// RUN: %clang_cc1 -mfentry -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=NOPG %s
+
+int foo(void) {
+ return 0;
+}
+
+//CHECK: attributes #{{[0-9]+}} = { {{.*}}"fentry-call"="true"{{.*}} }
+//NOPG-NOT: attributes #{{[0-9]+}} = { {{.*}}"fentry-call"{{.*}} }
diff --git a/test/CodeGen/ffp-contract-fast-option.cpp b/test/CodeGen/ffp-contract-fast-option.cpp
new file mode 100644
index 000000000000..3db93de107cd
--- /dev/null
+++ b/test/CodeGen/ffp-contract-fast-option.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+float fp_contract_1(float a, float b, float c) {
+ // CHECK-LABEL: fp_contract_1fff(
+ // CHECK: fmul contract float
+ // CHECK: fadd contract float
+ return a * b + c;
+}
+
+float fp_contract_2(float a, float b, float c) {
+ // CHECK-LABEL: fp_contract_2fff(
+ // CHECK: fmul contract float
+ // CHECK: fsub contract float
+ return a * b - c;
+}
+
+void fp_contract_3(float *a, float b, float c) {
+ // CHECK-LABEL: fp_contract_3Pfff(
+ // CHECK: fmul contract float
+ // CHECK: fadd contract float
+ a[0] += b * c;
+}
+
+void fp_contract_4(float *a, float b, float c) {
+ // CHECK-LABEL: fp_contract_4Pfff(
+ // CHECK: fmul contract float
+ // CHECK: fsub contract float
+ a[0] -= b * c;
+}
diff --git a/test/CodeGen/ffp-contract-option.c b/test/CodeGen/ffp-contract-option.c
index 61913b0aa333..52b750795940 100644
--- a/test/CodeGen/ffp-contract-option.c
+++ b/test/CodeGen/ffp-contract-option.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=powerpc-apple-darwin10 -S -o - %s | FileCheck %s
-// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=aarch64-apple-darwin -S -o - %s | FileCheck %s
+// REQUIRES: aarch64-registered-target
float fma_test1(float a, float b, float c) {
-// CHECK: fmadds
+// CHECK: fmadd
float x = a * b;
float y = x + c;
return y;
diff --git a/test/CodeGen/fp-contract-fast-pragma.cpp b/test/CodeGen/fp-contract-fast-pragma.cpp
new file mode 100644
index 000000000000..c2e52f070e93
--- /dev/null
+++ b/test/CodeGen/fp-contract-fast-pragma.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+// Is FP_CONTRACT honored in a simple case?
+float fp_contract_1(float a, float b, float c) {
+// CHECK: _Z13fp_contract_1fff
+// CHECK: %[[M:.+]] = fmul contract float %a, %b
+// CHECK-NEXT: fadd contract float %[[M]], %c
+#pragma clang fp contract(fast)
+ return a * b + c;
+}
+
+// Is FP_CONTRACT state cleared on exiting compound statements?
+float fp_contract_2(float a, float b, float c) {
+ // CHECK: _Z13fp_contract_2fff
+ // CHECK: %[[M:.+]] = fmul float %a, %b
+ // CHECK-NEXT: fadd float %[[M]], %c
+ {
+#pragma clang fp contract(fast)
+ }
+ return a * b + c;
+}
+
+// Does FP_CONTRACT survive template instantiation?
+class Foo {};
+Foo operator+(Foo, Foo);
+
+template <typename T>
+T template_muladd(T a, T b, T c) {
+#pragma clang fp contract(fast)
+ return a * b + c;
+}
+
+float fp_contract_3(float a, float b, float c) {
+ // CHECK: _Z13fp_contract_3fff
+ // CHECK: %[[M:.+]] = fmul contract float %a, %b
+ // CHECK-NEXT: fadd contract float %[[M]], %c
+ return template_muladd<float>(a, b, c);
+}
+
+template <typename T>
+class fp_contract_4 {
+ float method(float a, float b, float c) {
+#pragma clang fp contract(fast)
+ return a * b + c;
+ }
+};
+
+template class fp_contract_4<int>;
+// CHECK: _ZN13fp_contract_4IiE6methodEfff
+// CHECK: %[[M:.+]] = fmul contract float %a, %b
+// CHECK-NEXT: fadd contract float %[[M]], %c
+
+// Check file-scoped FP_CONTRACT
+#pragma clang fp contract(fast)
+float fp_contract_5(float a, float b, float c) {
+ // CHECK: _Z13fp_contract_5fff
+ // CHECK: %[[M:.+]] = fmul contract float %a, %b
+ // CHECK-NEXT: fadd contract float %[[M]], %c
+ return a * b + c;
+}
+
+// Verify that we can handle multiple flags on the same pragma
+#pragma clang fp contract(fast) contract(off)
+float fp_contract_6(float a, float b, float c) {
+ // CHECK: _Z13fp_contract_6fff
+ // CHECK: %[[M:.+]] = fmul float %a, %b
+ // CHECK-NEXT: fadd float %[[M]], %c
+ return a * b + c;
+}
diff --git a/test/CodeGen/fp-contract-on-pragma.cpp b/test/CodeGen/fp-contract-on-pragma.cpp
new file mode 100644
index 000000000000..812a7176b515
--- /dev/null
+++ b/test/CodeGen/fp-contract-on-pragma.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+// Is FP_CONTRACT honored in a simple case?
+float fp_contract_1(float a, float b, float c) {
+// CHECK: _Z13fp_contract_1fff
+// CHECK: tail call float @llvm.fmuladd
+#pragma clang fp contract(on)
+ return a * b + c;
+}
+
+// Is FP_CONTRACT state cleared on exiting compound statements?
+float fp_contract_2(float a, float b, float c) {
+ // CHECK: _Z13fp_contract_2fff
+ // CHECK: %[[M:.+]] = fmul float %a, %b
+ // CHECK-NEXT: fadd float %[[M]], %c
+ {
+#pragma clang fp contract(on)
+ }
+ return a * b + c;
+}
+
+// Does FP_CONTRACT survive template instantiation?
+class Foo {};
+Foo operator+(Foo, Foo);
+
+template <typename T>
+T template_muladd(T a, T b, T c) {
+#pragma clang fp contract(on)
+ return a * b + c;
+}
+
+float fp_contract_3(float a, float b, float c) {
+ // CHECK: _Z13fp_contract_3fff
+ // CHECK: tail call float @llvm.fmuladd
+ return template_muladd<float>(a, b, c);
+}
+
+template <typename T>
+class fp_contract_4 {
+ float method(float a, float b, float c) {
+#pragma clang fp contract(on)
+ return a * b + c;
+ }
+};
+
+template class fp_contract_4<int>;
+// CHECK: _ZN13fp_contract_4IiE6methodEfff
+// CHECK: tail call float @llvm.fmuladd
+
+// Check file-scoped FP_CONTRACT
+#pragma clang fp contract(on)
+float fp_contract_5(float a, float b, float c) {
+ // CHECK: _Z13fp_contract_5fff
+ // CHECK: tail call float @llvm.fmuladd
+ return a * b + c;
+}
+
+#pragma clang fp contract(off)
+float fp_contract_6(float a, float b, float c) {
+ // CHECK: _Z13fp_contract_6fff
+ // CHECK: %[[M:.+]] = fmul float %a, %b
+ // CHECK-NEXT: fadd float %[[M]], %c
+ return a * b + c;
+}
+
+// If the multiply has multiple uses, don't produce fmuladd.
+// This used to assert (PR25719):
+// https://llvm.org/bugs/show_bug.cgi?id=25719
+
+float fp_contract_7(float a, float b, float c) {
+// CHECK: _Z13fp_contract_7fff
+// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00
+// CHECK-NEXT: fsub float %[[M]], %c
+#pragma clang fp contract(on)
+ return (a = 2 * b) - c;
+}
diff --git a/test/CodeGen/function-sections.c b/test/CodeGen/function-sections.c
index 7994acf4dcac..c34216dec6c7 100644
--- a/test/CodeGen/function-sections.c
+++ b/test/CodeGen/function-sections.c
@@ -9,6 +9,12 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-data-sections -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
+// Try again through a clang invocation of the ThinLTO backend.
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O2 %s -flto=thin -emit-llvm-bc -o %t.o
+// RUN: llvm-lto -thinlto -o %t %t.o
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O2 -x ir %t.o -fthinlto-index=%t.thinlto.bc -S -ffunction-sections -o - | FileCheck %s --check-prefix=FUNC_SECT
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O2 -x ir %t.o -fthinlto-index=%t.thinlto.bc -S -fdata-sections -o - | FileCheck %s --check-prefix=DATA_SECT
+
const int hello = 123;
void world() {}
@@ -22,7 +28,7 @@ void world() {}
// FUNC_SECT: section .rodata,
// FUNC_SECT: hello:
-// DATA_SECT-NOT: section
+// DATA_SECT-NOT: .section
// DATA_SECT: world:
// DATA_SECT: .section .rodata.hello,
// DATA_SECT: hello:
diff --git a/test/CodeGen/libcall-declarations.c b/test/CodeGen/libcall-declarations.c
index 345b74fe97db..5a0b2ba0e636 100644
--- a/test/CodeGen/libcall-declarations.c
+++ b/test/CodeGen/libcall-declarations.c
@@ -402,9 +402,9 @@ void *use[] = {
// CHECK-NOERRNO: declare i32 @ilogb(double) [[NUW]]
// CHECK-NOERRNO: declare i32 @ilogbf(float) [[NUW]]
// CHECK-NOERRNO: declare i32 @ilogbl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @lgamma(double) [[NUW]]
-// CHECK-NOERRNO: declare float @lgammaf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @lgammal(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare double @lgamma(double) [[NONCONST:#[0-9]+]]
+// CHECK-NOERRNO: declare float @lgammaf(float) [[NONCONST]]
+// CHECK-NOERRNO: declare x86_fp80 @lgammal(x86_fp80) [[NONCONST]]
// CHECK-NOERRNO: declare i64 @llrint(double) [[NUW]]
// CHECK-NOERRNO: declare i64 @llrintf(float) [[NUW]]
// CHECK-NOERRNO: declare i64 @llrintl(x86_fp80) [[NUW]]
@@ -554,6 +554,9 @@ void *use[] = {
// CHECK-ERRNO: declare double @fmin(double, double) [[NUW]]
// CHECK-ERRNO: declare float @fminf(float, float) [[NUW]]
// CHECK-ERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare double @lgamma(double) [[NONCONST:#[0-9]+]]
+// CHECK-ERRNO: declare float @lgammaf(float) [[NONCONST]]
+// CHECK-ERRNO: declare x86_fp80 @lgammal(x86_fp80) [[NONCONST]]
// CHECK-ERRNO: declare double @nearbyint(double) [[NUW]]
// CHECK-ERRNO: declare float @nearbyintf(float) [[NUW]]
// CHECK-ERRNO: declare x86_fp80 @nearbyintl(x86_fp80) [[NUW]]
@@ -612,5 +615,11 @@ void *use[] = {
// CHECK-ERRNO: declare <2 x float> @ctanhf(<2 x float>) [[NUW]]
// CHECK-NOERRNO: attributes [[NUW]] = { nounwind readnone{{.*}} }
+// CHECK-NOERRNO: attributes [[NONCONST]] = {
+// CHECK-NOERRNO-NOT: readnone
+// CHECK-NOERRNO-SAME: nounwind{{.*}} }
+// CHECK-ERRNO: attributes [[NONCONST]] = {
+// CHECK-ERRNO-NOT: readnone
+// CHECK-ERRNO-SAME: nounwind{{.*}} }
// CHECK-ERRNO: attributes [[NUW]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGen/lifetime-asan.c b/test/CodeGen/lifetime-asan.c
index 5f0c66d513de..c5f25a2eaf75 100644
--- a/test/CodeGen/lifetime-asan.c
+++ b/test/CodeGen/lifetime-asan.c
@@ -8,14 +8,14 @@ extern int bar(char *A, int n);
// CHECK-O0-NOT: @llvm.lifetime.start
int foo(int n) {
if (n) {
- // CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.start(i64 10, i8* {{.*}})
+ // CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.start.p0i8(i64 10, i8* {{.*}})
char A[10];
return bar(A, 1);
- // CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.end(i64 10, i8* {{.*}})
+ // CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.end.p0i8(i64 10, i8* {{.*}})
} else {
- // CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.start(i64 20, i8* {{.*}})
+ // CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.start.p0i8(i64 20, i8* {{.*}})
char A[20];
return bar(A, 2);
- // CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.end(i64 20, i8* {{.*}})
+ // CHECK-ASAN-USE-AFTER-SCOPE: @llvm.lifetime.end.p0i8(i64 20, i8* {{.*}})
}
}
diff --git a/test/CodeGen/lifetime2.c b/test/CodeGen/lifetime2.c
index 4374b3c279c7..fcdcff36017e 100644
--- a/test/CodeGen/lifetime2.c
+++ b/test/CodeGen/lifetime2.c
@@ -1,7 +1,7 @@
-// RUN: %clang -S -emit-llvm -o - -O2 %s | FileCheck %s -check-prefixes=CHECK,O2
-// RUN: %clang -S -emit-llvm -o - -O2 -Xclang -disable-lifetime-markers %s \
+// RUN: %clang_cc1 -S -emit-llvm -o - -O2 -disable-llvm-passes %s | FileCheck %s -check-prefixes=CHECK,O2
+// RUN: %clang_cc1 -S -emit-llvm -o - -O2 -disable-lifetime-markers %s \
// RUN: | FileCheck %s -check-prefixes=CHECK,O0
-// RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefixes=CHECK,O0
+// RUN: %clang_cc1 -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefixes=CHECK,O0
extern int bar(char *A, int n);
@@ -21,24 +21,22 @@ int foo (int n) {
// CHECK-LABEL: @no_goto_bypass
void no_goto_bypass() {
- // O2: @llvm.lifetime.start(i64 1
+ // O2: @llvm.lifetime.start.p0i8(i64 1
char x;
l1:
bar(&x, 1);
- // O2: @llvm.lifetime.start(i64 5
- // O2: @llvm.lifetime.end(i64 5
char y[5];
bar(y, 5);
goto l1;
// Infinite loop
- // O2-NOT: @llvm.lifetime.end(i64 1
+ // O2-NOT: @llvm.lifetime.end.p0i8(
}
// CHECK-LABEL: @goto_bypass
void goto_bypass() {
{
- // O2-NOT: @llvm.lifetime.start(i64 1
- // O2-NOT: @llvm.lifetime.end(i64 1
+ // O2-NOT: @llvm.lifetime.start.p0i8(i64 1
+ // O2-NOT: @llvm.lifetime.end.p0i8(i64 1
char x;
l1:
bar(&x, 1);
@@ -50,16 +48,16 @@ void goto_bypass() {
void no_switch_bypass(int n) {
switch (n) {
case 1: {
- // O2: @llvm.lifetime.start(i64 1
- // O2: @llvm.lifetime.end(i64 1
+ // O2: @llvm.lifetime.start.p0i8(i64 1
+ // O2: @llvm.lifetime.end.p0i8(i64 1
char x;
bar(&x, 1);
break;
}
case 2:
n = n;
- // O2: @llvm.lifetime.start(i64 5
- // O2: @llvm.lifetime.end(i64 5
+ // O2: @llvm.lifetime.start.p0i8(i64 5
+ // O2: @llvm.lifetime.end.p0i8(i64 5
char y[5];
bar(y, 5);
break;
@@ -71,8 +69,8 @@ void switch_bypass(int n) {
switch (n) {
case 1:
n = n;
- // O2-NOT: @llvm.lifetime.start(i64 1
- // O2-NOT: @llvm.lifetime.end(i64 1
+ // O2-NOT: @llvm.lifetime.start.p0i8(i64 1
+ // O2-NOT: @llvm.lifetime.end.p0i8(i64 1
char x;
bar(&x, 1);
break;
@@ -91,3 +89,27 @@ void indirect_jump(int n) {
L:
bar(&x, 1);
}
+
+// O2-LABEL: @jump_backward_over_declaration(
+// O2: %[[p:.*]] = alloca i32*
+// O2: %[[v0:.*]] = bitcast i32** %[[p]] to i8*
+// O2: call void @llvm.lifetime.start.p0i8(i64 {{.*}}, i8* %[[v0]])
+// O2-NOT: call void @llvm.lifetime.start.p0i8(
+
+extern void foo2(int p);
+
+int jump_backward_over_declaration(int a) {
+ int *p = 0;
+label1:
+ if (p) {
+ foo2(*p);
+ return 0;
+ }
+
+ int i = 999;
+ if (a != 2) {
+ p = &i;
+ goto label1;
+ }
+ return -1;
+}
diff --git a/test/CodeGen/mmx-builtins.c b/test/CodeGen/mmx-builtins.c
index ddc6f66548ae..cd725e22b83c 100644
--- a/test/CodeGen/mmx-builtins.c
+++ b/test/CodeGen/mmx-builtins.c
@@ -383,6 +383,93 @@ __m64 test_mm_sad_pu8(__m64 a, __m64 b) {
return _mm_sad_pu8(a, b);
}
+__m64 test_mm_set_pi8(char a, char b, char c, char d, char e, char f, char g, char h) {
+ // CHECK-LABEL: test_mm_set_pi8
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ return _mm_set_pi8(a, b, c, d, e, f, g, h);
+}
+
+__m64 test_mm_set_pi16(short a, short b, short c, short d) {
+ // CHECK-LABEL: test_mm_set_pi16
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ return _mm_set_pi16(a, b, c, d);
+}
+
+__m64 test_mm_set_pi32(int a, int b) {
+ // CHECK-LABEL: test_mm_set_pi32
+ // CHECK: insertelement <2 x i32>
+ // CHECK: insertelement <2 x i32>
+ return _mm_set_pi32(a, b);
+}
+
+__m64 test_mm_setr_pi8(char a, char b, char c, char d, char e, char f, char g, char h) {
+ // CHECK-LABEL: test_mm_setr_pi8
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ return _mm_setr_pi8(a, b, c, d, e, f, g, h);
+}
+
+__m64 test_mm_setr_pi16(short a, short b, short c, short d) {
+ // CHECK-LABEL: test_mm_setr_pi16
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ return _mm_setr_pi16(a, b, c, d);
+}
+
+__m64 test_mm_setr_pi32(int a, int b) {
+ // CHECK-LABEL: test_mm_setr_pi32
+ // CHECK: insertelement <2 x i32>
+ // CHECK: insertelement <2 x i32>
+ return _mm_setr_pi32(a, b);
+}
+
+__m64 test_mm_set1_pi8(char a) {
+ // CHECK-LABEL: test_mm_set1_pi8
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ // CHECK: insertelement <8 x i8>
+ return _mm_set1_pi8(a);
+}
+
+__m64 test_mm_set1_pi16(short a) {
+ // CHECK-LABEL: test_mm_set1_pi16
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ // CHECK: insertelement <4 x i16>
+ return _mm_set1_pi16(a);
+}
+
+__m64 test_mm_set1_pi32(int a) {
+ // CHECK-LABEL: test_mm_set1_pi32
+ // CHECK: insertelement <2 x i32>
+ // CHECK: insertelement <2 x i32>
+ return _mm_set1_pi32(a);
+}
+
__m64 test_mm_shuffle_pi8(__m64 a, __m64 b) {
// CHECK-LABEL: test_mm_shuffle_pi8
// CHECK: call x86_mmx @llvm.x86.ssse3.pshuf.b
diff --git a/test/CodeGen/ms-declspecs.c b/test/CodeGen/ms-declspecs.c
index 4842050e5be5..05810bb4b71c 100644
--- a/test/CodeGen/ms-declspecs.c
+++ b/test/CodeGen/ms-declspecs.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -O2 -disable-llvm-optzns -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -O2 -disable-llvm-passes -o - | FileCheck %s
__declspec(selectany) int x1 = 1;
const __declspec(selectany) int x2 = 2;
diff --git a/test/CodeGen/ms-inline-asm-EVEN.c b/test/CodeGen/ms-inline-asm-EVEN.c
new file mode 100644
index 000000000000..a188af30910a
--- /dev/null
+++ b/test/CodeGen/ms-inline-asm-EVEN.c
@@ -0,0 +1,16 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -fasm-blocks -emit-llvm -o - | FileCheck %s
+
+// CHECK: .byte 64
+// CHECK: .byte 64
+// CHECK: .byte 64
+// CHECK: .even
+void t1() {
+ __asm {
+ .byte 64
+ .byte 64
+ .byte 64
+ EVEN
+ mov eax, ebx
+ }
+}
diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c
index 6efc09aec51d..c4fe08a3e13b 100644
--- a/test/CodeGen/ms-inline-asm.c
+++ b/test/CodeGen/ms-inline-asm.c
@@ -55,9 +55,15 @@ void t7() {
}
}
__asm {}
+ __asm {
+ ;
+ ; label
+ mov eax, ebx
+ }
// CHECK: t7
// CHECK: call void asm sideeffect inteldialect "int $$0x2cU", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, ebx", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
int t8() {
@@ -195,6 +201,8 @@ void t20() {
// CHECK: mov eax, $$4
__asm mov eax, LENGTH _bar
// CHECK: mov eax, $$2
+ __asm mov eax, [eax + LENGTH foo * 4]
+// CHECK: mov eax, [eax + $$1 * $$4]
__asm mov eax, TYPE foo
// CHECK: mov eax, $$4
@@ -204,6 +212,8 @@ void t20() {
// CHECK: mov eax, $$4
__asm mov eax, TYPE _bar
// CHECK: mov eax, $$1
+ __asm mov eax, [eax + TYPE foo * 4]
+// CHECK: mov eax, [eax + $$4 * $$4]
__asm mov eax, SIZE foo
// CHECK: mov eax, $$4
@@ -211,9 +221,12 @@ void t20() {
// CHECK: mov eax, $$1
__asm mov eax, SIZE _foo
// CHECK: mov eax, $$16
+ __asm mov eax, [eax + SIZE _foo * 4]
+// CHECK: mov eax, [eax + $$16 * $$4]
__asm mov eax, SIZE _bar
// CHECK: mov eax, $$2
// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
+
}
void t21() {
@@ -643,6 +656,14 @@ void label6(){
// CHECK: call void asm sideeffect inteldialect "jmp {{.*}}__MSASMLABEL_.${:uid}__label\0A\09{{.*}}__MSASMLABEL_.${:uid}__label:", "~{dirflag},~{fpsr},~{flags}"()
}
+// Don't include mxcsr in the clobber list.
+void mxcsr() {
+ char buf[4096];
+ __asm fxrstor buf
+}
+// CHECK-LABEL: define void @mxcsr
+// CHECK: call void asm sideeffect inteldialect "fxrstor byte ptr $0", "=*m,~{dirflag},~{fpsr},~{flags}"
+
typedef union _LARGE_INTEGER {
struct {
unsigned int LowPart;
diff --git a/test/CodeGen/ms-intrinsics.c b/test/CodeGen/ms-intrinsics.c
index 25eae44e0272..818be7fd7ffd 100644
--- a/test/CodeGen/ms-intrinsics.c
+++ b/test/CodeGen/ms-intrinsics.c
@@ -3,7 +3,7 @@
// RUN: | FileCheck %s -check-prefixes CHECK,CHECK-I386,CHECK-INTEL
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple thumbv7--windows -Oz -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-ARM-X64
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-ARM,CHECK-ARM-X64
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple x86_64--windows -Oz -emit-llvm %s -o - \
// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-X64,CHECK-ARM-X64,CHECK-INTEL
@@ -28,6 +28,20 @@ void test__stosb(unsigned char *Dest, unsigned char Data, size_t Count) {
// CHECK-X64: tail call void @llvm.memset.p0i8.i64(i8* %Dest, i8 %Data, i64 %Count, i32 1, i1 true)
// CHECK-X64: ret void
// CHECK-X64: }
+
+void test__ud2(void) {
+ __ud2();
+}
+// CHECK-INTEL-LABEL: define{{.*}} void @test__ud2()
+// CHECK-INTEL: call void @llvm.trap()
+
+void test__int2c(void) {
+ __int2c();
+}
+// CHECK-INTEL-LABEL: define{{.*}} void @test__int2c()
+// CHECK-INTEL: call void asm sideeffect "int $$0x2c", ""() #[[NORETURN:[0-9]+]]
+
+
#endif
void *test_ReturnAddress() {
@@ -419,3 +433,26 @@ __int64 test_InterlockedDecrement64(__int64 volatile *Addend) {
// CHECK-ARM-X64: }
#endif
+
+unsigned char test_interlockedbittestandset(volatile long *ptr, long bit) {
+ return _interlockedbittestandset(ptr, bit);
+}
+// CHECK-LABEL: define{{.*}} i8 @test_interlockedbittestandset
+// CHECK: [[MASKBIT:%[0-9]+]] = shl i32 1, %bit
+// CHECK: [[OLD:%[0-9]+]] = atomicrmw or i32* %ptr, i32 [[MASKBIT]] seq_cst
+// CHECK: [[SHIFT:%[0-9]+]] = lshr i32 [[OLD]], %bit
+// CHECK: [[TRUNC:%[0-9]+]] = trunc i32 [[SHIFT]] to i8
+// CHECK: [[AND:%[0-9]+]] = and i8 [[TRUNC]], 1
+// CHECK: ret i8 [[AND]]
+
+void test__fastfail() {
+ __fastfail(42);
+}
+// CHECK-LABEL: define{{.*}} void @test__fastfail()
+// CHECK-ARM: call void asm sideeffect "udf #251", "{r0}"(i32 42) #[[NORETURN:[0-9]+]]
+// CHECK-INTEL: call void asm sideeffect "int $$0x29", "{cx}"(i32 42) #[[NORETURN]]
+
+// Attributes come last.
+
+// CHECK: attributes #[[NORETURN]] = { noreturn{{.*}} }
+
diff --git a/test/CodeGen/ms-x86-intrinsics.c b/test/CodeGen/ms-x86-intrinsics.c
index e635220e8c13..51520d1f658b 100644
--- a/test/CodeGen/ms-x86-intrinsics.c
+++ b/test/CodeGen/ms-x86-intrinsics.c
@@ -6,15 +6,37 @@
// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-X64
#if defined(__i386__)
+char test__readfsbyte(unsigned long Offset) {
+ return __readfsbyte(Offset);
+}
+// CHECK-I386-LABEL: define signext i8 @test__readfsbyte(i32 %Offset)
+// CHECK-I386: [[PTR:%[0-9]+]] = inttoptr i32 %Offset to i8 addrspace(257)*
+// CHECK-I386: [[VALUE:%[0-9]+]] = load volatile i8, i8 addrspace(257)* [[PTR]], align 1
+// CHECK-I386: ret i8 [[VALUE:%[0-9]+]]
+
+short test__readfsword(unsigned long Offset) {
+ return __readfsword(Offset);
+}
+// CHECK-I386-LABEL: define signext i16 @test__readfsword(i32 %Offset)
+// CHECK-I386: [[PTR:%[0-9]+]] = inttoptr i32 %Offset to i16 addrspace(257)*
+// CHECK-I386: [[VALUE:%[0-9]+]] = load volatile i16, i16 addrspace(257)* [[PTR]], align 2
+// CHECK-I386: ret i16 [[VALUE:%[0-9]+]]
+
long test__readfsdword(unsigned long Offset) {
return __readfsdword(Offset);
}
-
-// CHECK-I386-LABEL: define i32 @test__readfsdword(i32 %Offset){{.*}}{
+// CHECK-I386-LABEL: define i32 @test__readfsdword(i32 %Offset)
// CHECK-I386: [[PTR:%[0-9]+]] = inttoptr i32 %Offset to i32 addrspace(257)*
// CHECK-I386: [[VALUE:%[0-9]+]] = load volatile i32, i32 addrspace(257)* [[PTR]], align 4
// CHECK-I386: ret i32 [[VALUE:%[0-9]+]]
-// CHECK-I386: }
+
+long long test__readfsqword(unsigned long Offset) {
+ return __readfsqword(Offset);
+}
+// CHECK-I386-LABEL: define i64 @test__readfsqword(i32 %Offset)
+// CHECK-I386: [[PTR:%[0-9]+]] = inttoptr i32 %Offset to i64 addrspace(257)*
+// CHECK-I386: [[VALUE:%[0-9]+]] = load volatile i64, i64 addrspace(257)* [[PTR]], align 8
+// CHECK-I386: ret i64 [[VALUE:%[0-9]+]]
#endif
__int64 test__emul(int a, int b) {
@@ -36,6 +58,43 @@ unsigned __int64 test__emulu(unsigned int a, unsigned int b) {
// CHECK: ret i64 [[RES]]
#if defined(__x86_64__)
+
+char test__readgsbyte(unsigned long Offset) {
+ return __readgsbyte(Offset);
+}
+// CHECK-X64-LABEL: define i8 @test__readgsbyte(i32 %Offset)
+// CHECK-X64: [[ZEXT:%[0-9]+]] = zext i32 %Offset to i64
+// CHECK-X64: [[PTR:%[0-9]+]] = inttoptr i64 [[ZEXT]] to i8 addrspace(256)*
+// CHECK-X64: [[VALUE:%[0-9]+]] = load volatile i8, i8 addrspace(256)* [[PTR]], align 1
+// CHECK-X64: ret i8 [[VALUE:%[0-9]+]]
+
+short test__readgsword(unsigned long Offset) {
+ return __readgsword(Offset);
+}
+// CHECK-X64-LABEL: define i16 @test__readgsword(i32 %Offset)
+// CHECK-X64: [[ZEXT:%[0-9]+]] = zext i32 %Offset to i64
+// CHECK-X64: [[PTR:%[0-9]+]] = inttoptr i64 [[ZEXT]] to i16 addrspace(256)*
+// CHECK-X64: [[VALUE:%[0-9]+]] = load volatile i16, i16 addrspace(256)* [[PTR]], align 2
+// CHECK-X64: ret i16 [[VALUE:%[0-9]+]]
+
+long test__readgsdword(unsigned long Offset) {
+ return __readgsdword(Offset);
+}
+// CHECK-X64-LABEL: define i32 @test__readgsdword(i32 %Offset)
+// CHECK-X64: [[ZEXT:%[0-9]+]] = zext i32 %Offset to i64
+// CHECK-X64: [[PTR:%[0-9]+]] = inttoptr i64 [[ZEXT]] to i32 addrspace(256)*
+// CHECK-X64: [[VALUE:%[0-9]+]] = load volatile i32, i32 addrspace(256)* [[PTR]], align 4
+// CHECK-X64: ret i32 [[VALUE:%[0-9]+]]
+
+long long test__readgsqword(unsigned long Offset) {
+ return __readgsqword(Offset);
+}
+// CHECK-X64-LABEL: define i64 @test__readgsqword(i32 %Offset)
+// CHECK-X64: [[ZEXT:%[0-9]+]] = zext i32 %Offset to i64
+// CHECK-X64: [[PTR:%[0-9]+]] = inttoptr i64 [[ZEXT]] to i64 addrspace(256)*
+// CHECK-X64: [[VALUE:%[0-9]+]] = load volatile i64, i64 addrspace(256)* [[PTR]], align 8
+// CHECK-X64: ret i64 [[VALUE:%[0-9]+]]
+
__int64 test__mulh(__int64 a, __int64 b) {
return __mulh(a, b);
}
diff --git a/test/CodeGen/object-size.c b/test/CodeGen/object-size.c
index a824f554b5f4..a1095798c16b 100644
--- a/test/CodeGen/object-size.c
+++ b/test/CodeGen/object-size.c
@@ -40,7 +40,7 @@ void test4() {
// CHECK-LABEL: define void @test5
void test5() {
// CHECK: = load i8*, i8** @gp
- // CHECK-NEXT:= call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK-NEXT:= call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
strcpy(gp, "Hi there");
}
@@ -254,31 +254,31 @@ struct Test23Ty { int a; int t[10]; };
// CHECK-LABEL: @test23
void test23(struct Test23Ty *p) {
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(p, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(p, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(p, 2);
// Note: this is currently fixed at 0 because LLVM doesn't have sufficient
// data to correctly handle type=3
// CHECK: store i32 0
gi = __builtin_object_size(p, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&p->a, 0);
// CHECK: store i32 4
gi = __builtin_object_size(&p->a, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(&p->a, 2);
// CHECK: store i32 4
gi = __builtin_object_size(&p->a, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&p->t[5], 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&p->t[5], 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(&p->t[5], 2);
// CHECK: store i32 20
gi = __builtin_object_size(&p->t[5], 3);
@@ -287,11 +287,11 @@ void test23(struct Test23Ty *p) {
// PR24493 -- ICE if __builtin_object_size called with NULL and (Type & 1) != 0
// CHECK-LABEL: @test24
void test24() {
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 true)
gi = __builtin_object_size((void*)0, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 true)
gi = __builtin_object_size((void*)0, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true, i1 true)
gi = __builtin_object_size((void*)0, 2);
// Note: Currently fixed at zero because LLVM can't handle type=3 correctly.
// Hopefully will be lowered properly in the future.
@@ -301,22 +301,22 @@ void test24() {
// CHECK-LABEL: @test25
void test25() {
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 true)
gi = __builtin_object_size((void*)0x1000, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 true)
gi = __builtin_object_size((void*)0x1000, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true, i1 true)
gi = __builtin_object_size((void*)0x1000, 2);
// Note: Currently fixed at zero because LLVM can't handle type=3 correctly.
// Hopefully will be lowered properly in the future.
// CHECK: store i32 0
gi = __builtin_object_size((void*)0x1000, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 true)
gi = __builtin_object_size((void*)0 + 0x1000, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 true)
gi = __builtin_object_size((void*)0 + 0x1000, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true, i1 true)
gi = __builtin_object_size((void*)0 + 0x1000, 2);
// Note: Currently fixed at zero because LLVM can't handle type=3 correctly.
// Hopefully will be lowered properly in the future.
@@ -342,22 +342,22 @@ struct Test27IncompleteTy;
// CHECK-LABEL: @test27
void test27(struct Test27IncompleteTy *t) {
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(t, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(t, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(t, 2);
// Note: this is currently fixed at 0 because LLVM doesn't have sufficient
// data to correctly handle type=3
// CHECK: store i32 0
gi = __builtin_object_size(t, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&test27, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&test27, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true, i1 true)
gi = __builtin_object_size(&test27, 2);
// Note: this is currently fixed at 0 because LLVM doesn't have sufficient
// data to correctly handle type=3
@@ -415,38 +415,38 @@ struct StaticStruct {
// CHECK-LABEL: @test29
void test29(struct DynStructVar *dv, struct DynStruct0 *d0,
struct DynStruct1 *d1, struct StaticStruct *ss) {
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(dv->snd, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(dv->snd, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(dv->snd, 2);
// CHECK: store i32 0
gi = __builtin_object_size(dv->snd, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(d0->snd, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(d0->snd, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(d0->snd, 2);
// CHECK: store i32 0
gi = __builtin_object_size(d0->snd, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(d1->snd, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(d1->snd, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(d1->snd, 2);
// CHECK: store i32 1
gi = __builtin_object_size(d1->snd, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(ss->snd, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(ss->snd, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(ss->snd, 2);
// CHECK: store i32 2
gi = __builtin_object_size(ss->snd, 3);
@@ -456,39 +456,39 @@ void test29(struct DynStructVar *dv, struct DynStruct0 *d0,
void test30() {
struct { struct DynStruct1 fst, snd; } *nested;
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(nested->fst.snd, 0);
// CHECK: store i32 1
gi = __builtin_object_size(nested->fst.snd, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(nested->fst.snd, 2);
// CHECK: store i32 1
gi = __builtin_object_size(nested->fst.snd, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(nested->snd.snd, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(nested->snd.snd, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(nested->snd.snd, 2);
// CHECK: store i32 1
gi = __builtin_object_size(nested->snd.snd, 3);
union { struct DynStruct1 d1; char c[1]; } *u;
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(u->c, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(u->c, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(u->c, 2);
// CHECK: store i32 1
gi = __builtin_object_size(u->c, 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(u->d1.snd, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(u->d1.snd, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(u->d1.snd, 2);
// CHECK: store i32 1
gi = __builtin_object_size(u->d1.snd, 3);
@@ -502,19 +502,19 @@ void test31() {
struct DynStruct1 *ds1;
struct StaticStruct *ss;
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(ds1[9].snd, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&ss[9].snd[0], 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&ds1[9].snd[0], 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&ds0[9].snd[0], 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&dsv[9].snd[0], 1);
}
@@ -527,11 +527,11 @@ void PR30346() {
};
struct sockaddr *sa;
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(sa->sa_data, 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(sa->sa_data, 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(sa->sa_data, 2);
// CHECK: store i32 14
gi = __builtin_object_size(sa->sa_data, 3);
diff --git a/test/CodeGen/object-size.cpp b/test/CodeGen/object-size.cpp
index 81b44a55a4e3..725c49214dd5 100644
--- a/test/CodeGen/object-size.cpp
+++ b/test/CodeGen/object-size.cpp
@@ -35,29 +35,29 @@ void test2() {
struct B : A {};
struct C { int i; B bs[1]; } *c;
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&c->bs[0], 0);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&c->bs[0], 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(&c->bs[0], 2);
// CHECK: store i32 16
gi = __builtin_object_size(&c->bs[0], 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size((A*)&c->bs[0], 0);
// CHECK: store i32 16
gi = __builtin_object_size((A*)&c->bs[0], 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size((A*)&c->bs[0], 2);
// CHECK: store i32 16
gi = __builtin_object_size((A*)&c->bs[0], 3);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true)
gi = __builtin_object_size(&c->bs[0].buf[0], 0);
// CHECK: store i32 16
gi = __builtin_object_size(&c->bs[0].buf[0], 1);
- // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true, i1 true)
gi = __builtin_object_size(&c->bs[0].buf[0], 2);
// CHECK: store i32 16
gi = __builtin_object_size(&c->bs[0].buf[0], 3);
diff --git a/test/CodeGen/opt-record-MIR.c b/test/CodeGen/opt-record-MIR.c
new file mode 100644
index 000000000000..00b91ffdf3cb
--- /dev/null
+++ b/test/CodeGen/opt-record-MIR.c
@@ -0,0 +1,33 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 -triple arm64-apple-ios -S -o /dev/null %s -O2 -dwarf-column-info -Rpass-missed=regalloc 2>&1 | FileCheck -check-prefix=REMARK %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -S -o /dev/null %s -O2 -dwarf-column-info 2>&1 | FileCheck -allow-empty -check-prefix=NO_REMARK %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -S -o /dev/null %s -O2 -dwarf-column-info -opt-record-file %t.yaml
+// RUN: cat %t.yaml | FileCheck -check-prefix=YAML %s
+
+void bar(float);
+
+void foo(float *p, int i) {
+ while (i--) {
+ float f = *p;
+ asm("" ::
+ : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp", "memory");
+ bar(f);
+ }
+}
+
+// REMARK: opt-record-MIR.c:10:11: remark: {{.}} spills {{.}} reloads generated in loop
+// NO_REMARK-NOT: remark:
+
+// YAML: --- !Missed
+// YAML: Pass: regalloc
+// YAML: Name: LoopSpillReload
+// YAML: DebugLoc: { File: {{.*}},
+// YAML: Line: 10, Column: 11 }
+// YAML: Function: foo
+// YAML: Args:
+// YAML: - NumSpills: '{{.}}'
+// YAML: - String: ' spills '
+// YAML: - NumReloads: '{{.}}'
+// YAML: - String: ' reloads '
+// YAML: - String: generated
+// YAML: ...
diff --git a/test/CodeGen/pass-object-size.c b/test/CodeGen/pass-object-size.c
index 6f5827befa71..f5c12317ec32 100644
--- a/test/CodeGen/pass-object-size.c
+++ b/test/CodeGen/pass-object-size.c
@@ -343,16 +343,26 @@ void test12(void *const p __attribute__((pass_object_size(3)))) {
// CHECK-LABEL: define void @test13
void test13() {
- // Ensuring that we don't lower objectsize if the expression has side-effects
char c[10];
+ unsigned i = 0;
char *p = c;
// CHECK: @llvm.objectsize
ObjectSize0(p);
- // CHECK-NOT: @llvm.objectsize
- ObjectSize0(++p);
- ObjectSize0(p++);
+ // Allow side-effects, since they always need to happen anyway. Just make sure
+ // we don't perform them twice.
+ // CHECK: = add
+ // CHECK-NOT: = add
+ // CHECK: @llvm.objectsize
+ // CHECK: call i32 @ObjectSize0
+ ObjectSize0(p + ++i);
+
+ // CHECK: = add
+ // CHECK: @llvm.objectsize
+ // CHECK-NOT: = add
+ // CHECK: call i32 @ObjectSize0
+ ObjectSize0(p + i++);
}
// There was a bug where variadic functions with pass_object_size would cause
@@ -369,3 +379,42 @@ void test14(char *c) {
// CHECK: call void (i8*, i64, ...) @my_sprintf
my_sprintf(c, 1, 2, 3);
}
+
+void pass_size_unsigned(unsigned *const PS(0));
+
+// Bug: we weren't lowering to the proper @llvm.objectsize for pointers that
+// don't turn into i8*s, which caused crashes.
+// CHECK-LABEL: define void @test15
+void test15(unsigned *I) {
+ // CHECK: @llvm.objectsize.i64.p0i32
+ // CHECK: call void @pass_size_unsigned
+ pass_size_unsigned(I);
+}
+
+void pass_size_as1(__attribute__((address_space(1))) void *const PS(0));
+
+void pass_size_unsigned_as1(
+ __attribute__((address_space(1))) unsigned *const PS(0));
+
+// CHECK-LABEL: define void @test16
+void test16(__attribute__((address_space(1))) unsigned *I) {
+ // CHECK: call i64 @llvm.objectsize.i64.p1i8
+ // CHECK: call void @pass_size_as1
+ pass_size_as1(I);
+ // CHECK: call i64 @llvm.objectsize.i64.p1i32
+ // CHECK: call void @pass_size_unsigned_as1
+ pass_size_unsigned_as1(I);
+}
+
+// This used to cause assertion failures, since we'd try to emit the statement
+// expression (and definitions for `a`) twice.
+// CHECK-LABEL: define void @test17
+void test17(char *C) {
+ // Check for 65535 to see if we're emitting this pointer twice.
+ // CHECK: 65535
+ // CHECK-NOT: 65535
+ // CHECK: @llvm.objectsize.i64.p0i8(i8* [[PTR:%[^,]+]],
+ // CHECK-NOT: 65535
+ // CHECK: call i32 @ObjectSize0(i8* [[PTR]]
+ ObjectSize0(C + ({ int a = 65535; a; }));
+}
diff --git a/test/CodeGen/pgo-sample-thinlto-summary.c b/test/CodeGen/pgo-sample-thinlto-summary.c
new file mode 100644
index 000000000000..a284af3c8087
--- /dev/null
+++ b/test/CodeGen/pgo-sample-thinlto-summary.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -O2 -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=O2
+// RUN: %clang_cc1 -O2 -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -flto=thin -o - 2>&1 | FileCheck %s -check-prefix=THINLTO
+// Checks if hot call is inlined by normal compile, but not inlined by
+// thinlto compile.
+
+int baz(int);
+int g;
+
+void foo(int n) {
+ for (int i = 0; i < n; i++)
+ g += baz(i);
+}
+
+// O2-LABEL: define void @bar
+// THINLTO-LABEL: define void @bar
+// O2-NOT: call{{.*}}foo
+// THINLTO: call{{.*}}foo
+void bar(int n) {
+ for (int i = 0; i < n; i++)
+ foo(i);
+}
+
+// Checks if loop unroll is invoked by normal compile, but not thinlto compile.
+// O2-LABEL: define void @unroll
+// THINLTO-LABEL: define void @unroll
+// O2: call{{.*}}baz
+// O2: call{{.*}}baz
+// THINLTO: call{{.*}}baz
+// THINLTO-NOT: call{{.*}}baz
+void unroll() {
+ for (int i = 0; i < 2; i++)
+ baz(i);
+}
+
+// Checks if icp is invoked by normal compile, but not thinlto compile.
+// O2-LABEL: define void @icp
+// THINLTO-LABEL: define void @icp
+// O2: if.true.direct_targ
+// ThinLTO-NOT: if.true.direct_targ
+void icp(void (*p)()) {
+ p();
+}
diff --git a/test/CodeGen/ppc64-align-struct.c b/test/CodeGen/ppc64-align-struct.c
index 6a04d0cd84f3..5894a6aeb379 100644
--- a/test/CodeGen/ppc64-align-struct.c
+++ b/test/CodeGen/ppc64-align-struct.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -faltivec -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
#include <stdarg.h>
diff --git a/test/CodeGen/ppc64-complex-parms.c b/test/CodeGen/ppc64-complex-parms.c
index 32163fa4a995..c0e1794bf47c 100644
--- a/test/CodeGen/ppc64-complex-parms.c
+++ b/test/CodeGen/ppc64-complex-parms.c
@@ -93,7 +93,7 @@ void bar_long_double(void) {
// CHECK: %[[VAR22:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0
// CHECK: %[[VAR23:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1
// CHECK: store ppc_fp128 0xM40000000000000000000000000000000, ppc_fp128* %[[VAR22]]
-// CHECK: store ppc_fp128 0xMC0040000000000000000000000000000, ppc_fp128* %[[VAR23]]
+// CHECK: store ppc_fp128 0xMC0040000000000008000000000000000, ppc_fp128* %[[VAR23]]
// CHECK: %[[VAR24:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0
// CHECK: %[[VAR25:[A-Za-z0-9.]+]] = load ppc_fp128, ppc_fp128* %[[VAR24]], align 16
// CHECK: %[[VAR26:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1
diff --git a/test/CodeGen/ppc64-vector.c b/test/CodeGen/ppc64-vector.c
index f0211f0ec197..87deb0f585ff 100644
--- a/test/CodeGen/ppc64-vector.c
+++ b/test/CodeGen/ppc64-vector.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -faltivec -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
typedef short v2i16 __attribute__((vector_size (4)));
typedef short v3i16 __attribute__((vector_size (6)));
diff --git a/test/CodeGen/ppc64le-aggregates.c b/test/CodeGen/ppc64le-aggregates.c
index 04d2fb4766ea..f78f26a59285 100644
--- a/test/CodeGen/ppc64le-aggregates.c
+++ b/test/CodeGen/ppc64le-aggregates.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -faltivec -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -target-feature +altivec -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
// Test homogeneous float aggregate passing and returning.
diff --git a/test/CodeGen/pr3997.c b/test/CodeGen/pr3997.c
new file mode 100644
index 000000000000..814144cd14d1
--- /dev/null
+++ b/test/CodeGen/pr3997.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -triple i386-unknown-linux-gnu -mregparm 3 -emit-llvm -o - | FileCheck %s
+
+void *memcpy(void *dest, const void *src, unsigned int n);
+
+void use_builtin_memcpy(void *dest, const void *src, unsigned int n) {
+ __builtin_memcpy(dest, src, n);
+}
+
+void use_memcpy(void *dest, const void *src, unsigned int n) {
+ memcpy(dest, src, n);
+}
+
+//CHECK: !{i32 1, !"NumRegisterParameters", i32 3}
diff --git a/test/CodeGen/sanitize-init-order.cpp b/test/CodeGen/sanitize-init-order.cpp
index 894f75e96739..f6a414084791 100644
--- a/test/CodeGen/sanitize-init-order.cpp
+++ b/test/CodeGen/sanitize-init-order.cpp
@@ -36,13 +36,13 @@ const volatile PODWithCtor array[5][5];
// Check that ASan init-order checking ignores structs with trivial default
// constructor.
-// CHECK: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]]], ![[GLOB_4:[0-9]]]}
+// CHECK: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]+]], ![[GLOB_4:[0-9]+]]
// CHECK: ![[GLOB_1]] = !{%struct.PODStruct* {{.*}}, i1 false, i1 false}
// CHECK: ![[GLOB_2]] = !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false}
// CHECK: ![[GLOB_3]] = !{%struct.PODWithCtorAndDtor* {{.*}}, i1 true, i1 false}
// CHECK: ![[GLOB_4]] = !{{{.*}}class.NS::PODWithCtor{{.*}}, i1 true, i1 false}
-// BLACKLIST: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]]], ![[GLOB_4:[0-9]]]}
+// BLACKLIST: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]+]], ![[GLOB_4:[0-9]+]]}
// BLACKLIST: ![[GLOB_1]] = !{%struct.PODStruct* {{.*}}, i1 false, i1 false}
// BLACKLIST: ![[GLOB_2]] = !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false}
// BLACKLIST: ![[GLOB_3]] = !{%struct.PODWithCtorAndDtor* {{.*}}, i1 false, i1 false}
diff --git a/test/CodeGen/sanitize-recover.c b/test/CodeGen/sanitize-recover.c
index dd8734e971eb..99eff8518ce8 100644
--- a/test/CodeGen/sanitize-recover.c
+++ b/test/CodeGen/sanitize-recover.c
@@ -19,20 +19,17 @@ void test() {
void foo() {
union { int i; } u;
u.i=1;
- // PARTIAL: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
-
- // PARTIAL: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
- // PARTIAL-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
+ // PARTIAL: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false, i1 false)
+ // PARTIAL-NEXT: %[[CHECK0:.*]] = icmp uge i64 %[[SIZE]], 4
// PARTIAL: %[[MISALIGN:.*]] = and i64 {{.*}}, 3
- // PARTIAL-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // PARTIAL-NEXT: %[[CHECK1:.*]] = icmp eq i64 %[[MISALIGN]], 0
- // PARTIAL: %[[CHECK02:.*]] = and i1 %[[CHECK0]], %[[CHECK2]]
- // PARTIAL-NEXT: %[[CHECK012:.*]] = and i1 %[[CHECK02]], %[[CHECK1]]
+ // PARTIAL: %[[CHECK01:.*]] = and i1 %[[CHECK1]], %[[CHECK0]]
- // PARTIAL: br i1 %[[CHECK012]], {{.*}} !prof ![[WEIGHT_MD:.*]], !nosanitize
+ // PARTIAL: br i1 %[[CHECK01]], {{.*}} !nosanitize
+ // PARTIAL: br i1 %[[CHECK1]], {{.*}} !nosanitize
- // PARTIAL: br i1 %[[CHECK02]], {{.*}}
// PARTIAL: call void @__ubsan_handle_type_mismatch_v1_abort(
// PARTIAL-NEXT: unreachable
// PARTIAL: call void @__ubsan_handle_type_mismatch_v1(
diff --git a/test/CodeGen/sanitize-thread-no-checking-at-run-time.m b/test/CodeGen/sanitize-thread-no-checking-at-run-time.m
index 098b7cf72ffd..3d862c0bf7ed 100644
--- a/test/CodeGen/sanitize-thread-no-checking-at-run-time.m
+++ b/test/CodeGen/sanitize-thread-no-checking-at-run-time.m
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -x objective-c++ -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -x objective-c++ -emit-llvm -o - %s -fsanitize=thread | FileCheck -check-prefix=TSAN %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -x objective-c++ -fblocks -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -x objective-c++ -fblocks -emit-llvm -o - %s -fsanitize=thread | FileCheck -check-prefix=TSAN %s
+
+// WITHOUT-NOT: "sanitize_thread_no_checking_at_run_time"
__attribute__((objc_root_class))
@interface NSObject
@@ -26,9 +28,14 @@ public:
}
@end
-// WITHOUT-NOT: "sanitize_thread_no_checking_at_run_time"
-
// TSAN: initialize{{.*}}) [[ATTR:#[0-9]+]]
// TSAN: dealloc{{.*}}) [[ATTR:#[0-9]+]]
// TSAN: cxx_destruct{{.*}}) [[ATTR:#[0-9]+]]
+
+void test2(id x) {
+ extern void test2_helper(id (^)(void));
+ test2_helper(^{ return x; });
+// TSAN: define internal void @__destroy_helper_block_(i8*) [[ATTR:#[0-9]+]]
+}
+
// TSAN: attributes [[ATTR]] = { noinline nounwind {{.*}} "sanitize_thread_no_checking_at_run_time" {{.*}} }
diff --git a/test/CodeGen/sse-builtins.c b/test/CodeGen/sse-builtins.c
index 27b016f66517..28b4f2cae1f0 100644
--- a/test/CodeGen/sse-builtins.c
+++ b/test/CodeGen/sse-builtins.c
@@ -802,7 +802,7 @@ int test_mm_ucomineq_ss(__m128 A, __m128 B) {
__m128 test_mm_undefined_ps() {
// CHECK-LABEL: @test_mm_undefined_ps
- // CHECK: ret <4 x float> undef
+ // CHECK: ret <4 x float> zeroinitializer
return _mm_undefined_ps();
}
diff --git a/test/CodeGen/sse2-builtins.c b/test/CodeGen/sse2-builtins.c
index 48c703685479..a140a6ce55b5 100644
--- a/test/CodeGen/sse2-builtins.c
+++ b/test/CodeGen/sse2-builtins.c
@@ -1455,13 +1455,13 @@ int test_mm_ucomineq_sd(__m128d A, __m128d B) {
__m128d test_mm_undefined_pd() {
// CHECK-LABEL: @test_mm_undefined_pd
- // CHECK: ret <2 x double> undef
+ // CHECK: ret <2 x double> zeroinitializer
return _mm_undefined_pd();
}
__m128i test_mm_undefined_si128() {
// CHECK-LABEL: @test_mm_undefined_si128
- // CHECK: ret <2 x i64> undef
+ // CHECK: ret <2 x i64> zeroinitializer
return _mm_undefined_si128();
}
diff --git a/test/CodeGen/sse41-builtins.c b/test/CodeGen/sse41-builtins.c
index adf9609b68f9..b48b73ec18d9 100644
--- a/test/CodeGen/sse41-builtins.c
+++ b/test/CodeGen/sse41-builtins.c
@@ -354,7 +354,7 @@ __m128 test_mm_round_ss(__m128 x, __m128 y) {
__m128i test_mm_stream_load_si128(__m128i const *a) {
// CHECK-LABEL: test_mm_stream_load_si128
- // CHECK: call <2 x i64> @llvm.x86.sse41.movntdqa(i8* %{{.*}})
+ // CHECK: load <2 x i64>, <2 x i64>* %{{.*}}, align 16, !nontemporal
return _mm_stream_load_si128(a);
}
diff --git a/test/CodeGen/temporary-lifetime-exceptions.cpp b/test/CodeGen/temporary-lifetime-exceptions.cpp
index f435560c9759..1dc1c40dc6ba 100644
--- a/test/CodeGen/temporary-lifetime-exceptions.cpp
+++ b/test/CodeGen/temporary-lifetime-exceptions.cpp
@@ -9,16 +9,16 @@ A Baz(const A&);
void Test1() {
// CHECK-LABEL: @_Z5Test1v(
// CHECK: getelementptr
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* nonnull [[TMP:[^ ]+]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP:[^ ]+]])
// CHECK-NEXT: getelementptr
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* nonnull [[TMP1:[^ ]+]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1:[^ ]+]])
// Normal exit
- // CHECK: call void @llvm.lifetime.end(i64 1, i8* nonnull [[TMP1]])
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* nonnull [[TMP]])
+ // CHECK: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP]])
// Exception exit
- // CHECK: call void @llvm.lifetime.end(i64 1, i8* nonnull [[TMP1]])
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* nonnull [[TMP]])
+ // CHECK: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP]])
Baz(Baz(A()));
}
diff --git a/test/CodeGen/temporary-lifetime.cpp b/test/CodeGen/temporary-lifetime.cpp
index f105a441a367..309b4e52da52 100644
--- a/test/CodeGen/temporary-lifetime.cpp
+++ b/test/CodeGen/temporary-lifetime.cpp
@@ -21,27 +21,27 @@ T Baz();
void Test1() {
// CHECK-DTOR-LABEL: Test1
- // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
+ // CHECK-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
// CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]])
// CHECK-DTOR: call void @_Z3FooIRK1AEvOT_
// CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR]])
- // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR]])
- // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
+ // CHECK-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR]])
+ // CHECK-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
// CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]])
// CHECK-DTOR: call void @_Z3FooIRK1AEvOT_
// CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR]])
- // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR]])
+ // CHECK-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR]])
// CHECK-DTOR: }
// CHECK-NO-DTOR-LABEL: Test1
- // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
+ // CHECK-NO-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
// CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]])
// CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_
- // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR]])
- // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
+ // CHECK-NO-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR]])
+ // CHECK-NO-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
// CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]])
// CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_
- // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR]])
+ // CHECK-NO-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR]])
// CHECK-NO-DTOR: }
{
const A &a = A{};
@@ -55,27 +55,27 @@ void Test1() {
void Test2() {
// CHECK-DTOR-LABEL: Test2
- // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR1:[0-9]+]])
+ // CHECK-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR1:[0-9]+]])
// CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR1:[^ ]+]])
// CHECK-DTOR: call void @_Z3FooIRK1AEvOT_
- // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR2:[0-9]+]])
+ // CHECK-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR2:[0-9]+]])
// CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR2:[^ ]+]])
// CHECK-DTOR: call void @_Z3FooIRK1AEvOT_
// CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR2]])
- // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR2]])
+ // CHECK-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR2]])
// CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR1]])
- // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR1]])
+ // CHECK-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR1]])
// CHECK-DTOR: }
// CHECK-NO-DTOR-LABEL: Test2
- // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR1:[0-9]+]])
+ // CHECK-NO-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR1:[0-9]+]])
// CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR1:[^ ]+]])
// CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_
- // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR2:[0-9]+]])
+ // CHECK-NO-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR2:[0-9]+]])
// CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR2:[^ ]+]])
// CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_
- // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR2]])
- // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR1]])
+ // CHECK-NO-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR2]])
+ // CHECK-NO-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR1]])
// CHECK-NO-DTOR: }
const A &a = A{};
Foo(a);
@@ -135,16 +135,16 @@ int Test5() {
void Test6() {
// CHECK-DTOR-LABEL: Test6
- // CHECK-DTOR: call void @llvm.lifetime.start(i64 {{[0-9]+}}, i8* nonnull %[[ADDR:[0-9]+]])
+ // CHECK-DTOR: call void @llvm.lifetime.start.p0i8(i64 {{[0-9]+}}, i8* nonnull %[[ADDR:[0-9]+]])
// CHECK-DTOR: call i32 @_Z3BazIiET_v()
// CHECK-DTOR: store
// CHECK-DTOR: call void @_Z3FooIiEvOT_
- // CHECK-DTOR: call void @llvm.lifetime.end(i64 {{[0-9]+}}, i8* nonnull %[[ADDR]])
- // CHECK-DTOR: call void @llvm.lifetime.start(i64 {{[0-9]+}}, i8* nonnull %[[ADDR:[0-9]+]])
+ // CHECK-DTOR: call void @llvm.lifetime.end.p0i8(i64 {{[0-9]+}}, i8* nonnull %[[ADDR]])
+ // CHECK-DTOR: call void @llvm.lifetime.start.p0i8(i64 {{[0-9]+}}, i8* nonnull %[[ADDR:[0-9]+]])
// CHECK-DTOR: call i32 @_Z3BazIiET_v()
// CHECK-DTOR: store
// CHECK-DTOR: call void @_Z3FooIiEvOT_
- // CHECK-DTOR: call void @llvm.lifetime.end(i64 {{[0-9]+}}, i8* nonnull %[[ADDR]])
+ // CHECK-DTOR: call void @llvm.lifetime.end.p0i8(i64 {{[0-9]+}}, i8* nonnull %[[ADDR]])
// CHECK-DTOR: }
Foo(Baz<int>());
Foo(Baz<int>());
@@ -152,16 +152,16 @@ void Test6() {
void Test7() {
// CHECK-DTOR-LABEL: Test7
- // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
+ // CHECK-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
// CHECK-DTOR: call void @_Z3BazI1AET_v({{.*}} %[[SLOT:[^ ]+]])
// CHECK-DTOR: call void @_Z3FooI1AEvOT_({{.*}} %[[SLOT]])
// CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[SLOT]])
- // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR]])
- // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
+ // CHECK-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR]])
+ // CHECK-DTOR: call void @llvm.lifetime.start.p0i8(i64 1024, i8* nonnull %[[ADDR:[0-9]+]])
// CHECK-DTOR: call void @_Z3BazI1AET_v({{.*}} %[[SLOT:[^ ]+]])
// CHECK-DTOR: call void @_Z3FooI1AEvOT_({{.*}} %[[SLOT]])
// CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[SLOT]])
- // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* nonnull %[[ADDR]])
+ // CHECK-DTOR: call void @llvm.lifetime.end.p0i8(i64 1024, i8* nonnull %[[ADDR]])
// CHECK-DTOR: }
Foo(Baz<A>());
Foo(Baz<A>());
diff --git a/test/CodeGen/thin_link_bitcode.c b/test/CodeGen/thin_link_bitcode.c
new file mode 100644
index 000000000000..4cb5f798a568
--- /dev/null
+++ b/test/CodeGen/thin_link_bitcode.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -o %t -flto=thin -fthin-link-bitcode=%t.nodebug -triple x86_64-unknown-linux-gnu -emit-llvm-bc -debug-info-kind=limited %s
+// RUN: llvm-bcanalyzer -dump %t | FileCheck %s
+// RUN: llvm-bcanalyzer -dump %t.nodebug | FileCheck %s --check-prefix=NO_DEBUG
+int main (void) {
+ return 0;
+}
+
+// CHECK: COMPILE_UNIT
+// NO_DEBUG-NOT: COMPILE_UNIT
diff --git a/test/CodeGen/thinlto-emit-llvm.c b/test/CodeGen/thinlto-emit-llvm.c
new file mode 100644
index 000000000000..f611162d1999
--- /dev/null
+++ b/test/CodeGen/thinlto-emit-llvm.c
@@ -0,0 +1,10 @@
+// Test to ensure -emit-llvm and -emit-llvm-bc work when invoking the
+// ThinLTO backend path.
+// RUN: %clang -O2 %s -flto=thin -c -o %t.o
+// RUN: llvm-lto -thinlto -o %t %t.o
+// RUN: %clang_cc1 -O2 -x ir %t.o -fthinlto-index=%t.thinlto.bc -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -O2 -x ir %t.o -fthinlto-index=%t.thinlto.bc -emit-llvm-bc -o - | llvm-dis -o - | FileCheck %s
+
+// CHECK: define void @foo()
+void foo() {
+}
diff --git a/test/CodeGen/thinlto-multi-module.ll b/test/CodeGen/thinlto-multi-module.ll
new file mode 100644
index 000000000000..21d28cf44da2
--- /dev/null
+++ b/test/CodeGen/thinlto-multi-module.ll
@@ -0,0 +1,22 @@
+; REQUIRES: x86-registered-target
+
+; RUN: opt -module-summary -o %t1.o %s
+; RUN: llvm-lto -thinlto -o %t %t1.o
+
+; RUN: opt -o %t2.o %S/Inputs/thinlto_backend.ll
+; RUN: llvm-cat -b -o %t1cat.o %t1.o %t2.o
+; RUN: cp %t1cat.o %t1.o
+; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t3.o -x ir %t1.o -c -fthinlto-index=%t.thinlto.bc
+; RUN: llvm-nm %t3.o | FileCheck --check-prefix=CHECK-OBJ %s
+; CHECK-OBJ: T f1
+; CHECK-OBJ: U f2
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @f2()
+
+define void @f1() {
+ call void @f2()
+ ret void
+}
diff --git a/test/CodeGen/transparent-union.c b/test/CodeGen/transparent-union.c
index 2f00c2d21a05..efaef1bae987 100644
--- a/test/CodeGen/transparent-union.c
+++ b/test/CodeGen/transparent-union.c
@@ -3,10 +3,21 @@
// RUN: %clang_cc1 -Werror -triple armv7-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM
// RUN: %clang_cc1 -Werror -triple powerpc64le-linux -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -Werror -triple aarch64-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -DINFRONT -Werror -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -DINFRONT -Werror -triple i386-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -DINFRONT -Werror -triple armv7-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM
+// RUN: %clang_cc1 -DINFRONT -Werror -triple powerpc64le-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -DINFRONT -Werror -triple aarch64-linux -emit-llvm -o - %s | FileCheck %s
+#ifdef INFRONT
+typedef union __attribute__((transparent_union)) {
+ void *f0;
+} transp_t0;
+#else
typedef union {
void *f0;
} transp_t0 __attribute__((transparent_union));
+#endif
void f0(transp_t0 obj);
diff --git a/test/CodeGen/ubsan-promoted-arith.cpp b/test/CodeGen/ubsan-promoted-arith.cpp
new file mode 100644
index 000000000000..5a2898b5423b
--- /dev/null
+++ b/test/CodeGen/ubsan-promoted-arith.cpp
@@ -0,0 +1,131 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=signed-integer-overflow,unsigned-integer-overflow | FileCheck %s
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef int int4 __attribute__((ext_vector_type(4)));
+
+enum E1 : int {
+ a
+};
+
+enum E2 : char {
+ b
+};
+
+// CHECK-LABEL: define signext i8 @_Z4add1
+// CHECK-NOT: sadd.with.overflow
+char add1(char c) { return c + c; }
+
+// CHECK-LABEL: define zeroext i8 @_Z4add2
+// CHECK-NOT: uadd.with.overflow
+uchar add2(uchar uc) { return uc + uc; }
+
+// CHECK-LABEL: define i32 @_Z4add3
+// CHECK: sadd.with.overflow
+int add3(E1 e) { return e + a; }
+
+// CHECK-LABEL: define signext i8 @_Z4add4
+// CHECK-NOT: sadd.with.overflow
+char add4(E2 e) { return e + b; }
+
+// CHECK-LABEL: define signext i8 @_Z4sub1
+// CHECK-NOT: ssub.with.overflow
+char sub1(char c) { return c - c; }
+
+// CHECK-LABEL: define zeroext i8 @_Z4sub2
+// CHECK-NOT: usub.with.overflow
+uchar sub2(uchar uc) { return uc - uc; }
+
+// CHECK-LABEL: define signext i8 @_Z4sub3
+// CHECK-NOT: ssub.with.overflow
+char sub3(char c) { return -c; }
+
+// Note: -INT_MIN can overflow.
+//
+// CHECK-LABEL: define i32 @_Z4sub4
+// CHECK: ssub.with.overflow
+int sub4(int i) { return -i; }
+
+// CHECK-LABEL: define signext i8 @_Z4mul1
+// CHECK-NOT: smul.with.overflow
+char mul1(char c) { return c * c; }
+
+// CHECK-LABEL: define zeroext i8 @_Z4mul2
+// CHECK-NOT: smul.with.overflow
+uchar mul2(uchar uc) { return uc * uc; }
+
+// Note: USHRT_MAX * USHRT_MAX can overflow.
+//
+// CHECK-LABEL: define zeroext i16 @_Z4mul3
+// CHECK: smul.with.overflow
+ushort mul3(ushort us) { return us * us; }
+
+// CHECK-LABEL: define i32 @_Z4mul4
+// CHECK: smul.with.overflow
+int mul4(int i, char c) { return i * c; }
+
+// CHECK-LABEL: define i32 @_Z4mul5
+// CHECK: smul.with.overflow
+int mul5(int i, char c) { return c * i; }
+
+// CHECK-LABEL: define signext i16 @_Z4mul6
+// CHECK-NOT: smul.with.overflow
+short mul6(short s) { return s * s; }
+
+// CHECK-LABEL: define signext i8 @_Z4div1
+// CHECK-NOT: ubsan_handle_divrem_overflow
+char div1(char c) { return c / c; }
+
+// CHECK-LABEL: define zeroext i8 @_Z4div2
+// CHECK-NOT: ubsan_handle_divrem_overflow
+uchar div2(uchar uc) { return uc / uc; }
+
+// CHECK-LABEL: define signext i8 @_Z4div3
+// CHECK-NOT: ubsan_handle_divrem_overflow
+char div3(char c, int i) { return c / i; }
+
+// CHECK-LABEL: define signext i8 @_Z4div4
+// CHECK: ubsan_handle_divrem_overflow
+char div4(int i, char c) { return i / c; }
+
+// Note: INT_MIN / -1 can overflow.
+//
+// CHECK-LABEL: define signext i8 @_Z4div5
+// CHECK: ubsan_handle_divrem_overflow
+char div5(int i, char c) { return i / c; }
+
+// CHECK-LABEL: define signext i8 @_Z4rem1
+// CHECK-NOT: ubsan_handle_divrem_overflow
+char rem1(char c) { return c % c; }
+
+// CHECK-LABEL: define zeroext i8 @_Z4rem2
+// CHECK-NOT: ubsan_handle_divrem_overflow
+uchar rem2(uchar uc) { return uc % uc; }
+
+// CHECK-LABEL: define signext i8 @_Z4rem3
+// CHECK: ubsan_handle_divrem_overflow
+char rem3(int i, char c) { return i % c; }
+
+// CHECK-LABEL: define signext i8 @_Z4rem4
+// CHECK-NOT: ubsan_handle_divrem_overflow
+char rem4(char c, int i) { return c % i; }
+
+// CHECK-LABEL: define signext i8 @_Z4inc1
+// CHECK-NOT: sadd.with.overflow
+char inc1(char c) { return c++ + (char)0; }
+
+// CHECK-LABEL: define zeroext i8 @_Z4inc2
+// CHECK-NOT: uadd.with.overflow
+uchar inc2(uchar uc) { return uc++ + (uchar)0; }
+
+// CHECK-LABEL: define void @_Z4inc3
+// CHECK-NOT: sadd.with.overflow
+void inc3(char c) { c++; }
+
+// CHECK-LABEL: define void @_Z4inc4
+// CHECK-NOT: uadd.with.overflow
+void inc4(uchar uc) { uc++; }
+
+// CHECK-LABEL: define <4 x i32> @_Z4vremDv4_iS_
+// CHECK-NOT: ubsan_handle_divrem_overflow
+int4 vrem(int4 a, int4 b) { return a % b; }
diff --git a/test/CodeGen/ubsan-shift.c b/test/CodeGen/ubsan-shift.c
new file mode 100644
index 000000000000..90c15d8c086f
--- /dev/null
+++ b/test/CodeGen/ubsan-shift.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -fsanitize=shift-exponent,shift-base -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: define i32 @f1
+int f1(int c, int shamt) {
+// CHECK: icmp ule i32 %{{.*}}, 31, !nosanitize
+// CHECK: icmp ule i32 %{{.*}}, 31, !nosanitize
+ return 1 << (c << shamt);
+}
+
+// CHECK-LABEL: define i32 @f2
+int f2(long c, int shamt) {
+// CHECK: icmp ule i32 %{{.*}}, 63, !nosanitize
+// CHECK: icmp ule i64 %{{.*}}, 31, !nosanitize
+ return 1 << (c << shamt);
+}
+
+// CHECK-LABEL: define i32 @f3
+unsigned f3(unsigned c, int shamt) {
+// CHECK: icmp ule i32 %{{.*}}, 31, !nosanitize
+// CHECK: icmp ule i32 %{{.*}}, 31, !nosanitize
+ return 1U << (c << shamt);
+}
+
+// CHECK-LABEL: define i32 @f4
+unsigned f4(unsigned long c, int shamt) {
+// CHECK: icmp ule i32 %{{.*}}, 63, !nosanitize
+// CHECK: icmp ule i64 %{{.*}}, 31, !nosanitize
+ return 1U << (c << shamt);
+}
+
+// CHECK-LABEL: define i32 @f5
+int f5(int c, long long shamt) {
+// CHECK: icmp ule i64 %{{[0-9]+}}, 31, !nosanitize
+//
+// CHECK: sub nuw nsw i32 31, %sh_prom, !nosanitize
+// CHECK: lshr i32 %{{.*}}, %shl.zeros, !nosanitize
+ return c << shamt;
+}
+
+// CHECK-LABEL: define i32 @f6
+int f6(int c, int shamt) {
+// CHECK: icmp ule i32 %[[WIDTH:.*]], 31, !nosanitize
+//
+// CHECK: sub nuw nsw i32 31, %[[WIDTH]], !nosanitize
+// CHECK: lshr i32 %{{.*}}, %shl.zeros, !nosanitize
+ return c << shamt;
+}
diff --git a/test/CodeGen/unaligned-decl.c b/test/CodeGen/unaligned-decl.c
new file mode 100644
index 000000000000..d5d32bd830fa
--- /dev/null
+++ b/test/CodeGen/unaligned-decl.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fms-extensions -emit-llvm < %s | FileCheck %s
+
+// CHECK: @a1 = global i32 1, align 1
+__unaligned int a1 = 1;
+
+// CHECK: @a2 = global i32 1, align 1
+int __unaligned a2 = 1;
+
+// CHECK: @a3 = {{.*}} align 1
+__unaligned int a3[10];
+
+// CHECK: @a4 = {{.*}} align 1
+int __unaligned a4[10];
+
+// CHECK: @p1 = {{.*}} align 1
+int *__unaligned p1;
+
+// CHECK: @p2 = {{.*}} align 8
+int __unaligned *p2;
+
+// CHECK: @p3 = {{.*}} align 1
+int __unaligned *__unaligned p3;
diff --git a/test/CodeGen/unaligned-expr.c b/test/CodeGen/unaligned-expr.c
new file mode 100644
index 000000000000..6e23cbc729fb
--- /dev/null
+++ b/test/CodeGen/unaligned-expr.c
@@ -0,0 +1,217 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fms-extensions -emit-llvm < %s | FileCheck %s
+
+// -------------
+// Scalar integer
+// -------------
+__unaligned int x;
+void test1(void) {
+ // CHECK: {{%.*}} = load i32, i32* @x, align 1
+ // CHECK: store i32 {{%.*}}, i32* @x, align 1
+ x++;
+}
+
+void test2(void) {
+ // CHECK: %y = alloca i32, align 1
+ // CHECK: {{%.*}} = load i32, i32* %y, align 1
+ // CHECK: store i32 {{%.*}}, i32* %y, align 1
+ __unaligned int y;
+ y++;
+}
+
+void test2_1(void) {
+ // CHECK: %y = alloca i32, align 1
+ // CHECK: store i32 1, i32* %y, align 1
+ __unaligned int y = 1;
+}
+
+// -------------
+// Global pointer
+// -------------
+int *__unaligned p1;
+void test3(void) {
+
+ // CHECK: {{%.*}} = load i32*, i32** @p1, align 1
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 4
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 4
+ (*p1)++;
+}
+
+int __unaligned *p2;
+void test4(void) {
+ // CHECK: {{%.*}} = load i32*, i32** @p2, align 8
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 1
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 1
+ (*p2)++;
+}
+
+int __unaligned *__unaligned p3;
+void test5(void) {
+ // CHECK: {{%.*}} = load i32*, i32** @p3, align 1
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 1
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 1
+ (*p3)++;
+}
+
+// -------------
+// Local pointer
+// -------------
+void test6(void) {
+ // CHECK: %lp1 = alloca i32*, align 1
+ // CHECK: {{%.*}} = load i32*, i32** %lp1, align 1
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 4
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 4
+ int *__unaligned lp1;
+ (*lp1)++;
+}
+
+void test7(void) {
+ // CHECK: %lp2 = alloca i32*, align 8
+ // CHECK: {{%.*}} = load i32*, i32** %lp2, align 8
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 1
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 1
+ int __unaligned *lp2;
+ (*lp2)++;
+}
+
+void test8(void) {
+ // CHECK: %lp3 = alloca i32*, align 1
+ // CHECK: {{%.*}} = load i32*, i32** %lp3, align 1
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 1
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 1
+ int __unaligned *__unaligned lp3;
+ (*lp3)++;
+}
+
+// -------------
+// Global array
+// -------------
+__unaligned int a[10];
+void test9(void) {
+ // CHECK: {{%.*}} = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @a, i64 0, i64 3), align 1
+ // CHECK: store i32 {{%.*}}, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @a, i64 0, i64 3), align 1
+ (a[3])++;
+}
+
+// -------------
+// Local array
+// -------------
+void test10(void) {
+ // CHECK: %la = alloca [10 x i32], align 1
+ // CHECK: {{%.*}} = getelementptr inbounds [10 x i32], [10 x i32]* %la, i64 0, i64 3
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 1
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 1
+ __unaligned int la[10];
+ (la[3])++;
+}
+
+// --------
+// Typedefs
+// --------
+
+typedef __unaligned int UnalignedInt;
+void test13() {
+ // CHECK: %i = alloca i32, align 1
+ // CHECK: {{%.*}} = load i32, i32* %i, align 1
+ // CHECK: store i32 {{%.*}}, i32* %i, align 1
+ UnalignedInt i;
+ i++;
+}
+
+typedef int Aligned;
+typedef __unaligned Aligned UnalignedInt2;
+void test14() {
+ // CHECK: %i = alloca i32, align 1
+ // CHECK: {{%.*}} = load i32, i32* %i, align 1
+ // CHECK: store i32 {{%.*}}, i32* %i, align 1
+ UnalignedInt2 i;
+ i++;
+}
+
+typedef UnalignedInt UnalignedInt3;
+void test15() {
+ // CHECK: %i = alloca i32, align 1
+ // CHECK: {{%.*}} = load i32, i32* %i, align 1
+ // CHECK: store i32 {{%.*}}, i32* %i, align 1
+ UnalignedInt3 i;
+ i++;
+}
+
+// -------------
+// Decayed types
+// -------------
+void test16(__unaligned int c[10]) {
+ // CHECK: {{%.*}} = alloca i32*, align 8
+ // CHECK: store i32* %c, i32** {{%.*}}, align 8
+ // CHECK: {{%.*}} = load i32*, i32** {{%.*}}, align 8
+ // CHECK: {{%.*}} = getelementptr inbounds i32, i32* {{%.*}}, i64 3
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 1
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 1
+ c[3]++;
+}
+
+// -----------
+// __alignof__
+// -----------
+int test17(void) {
+ // CHECK: ret i32 1
+ return __alignof__(__unaligned int);
+}
+
+int test18(void) {
+ // CHECK: ret i32 1
+ __unaligned int a;
+ return __alignof__(a);
+}
+
+int test19(void) {
+ // CHECK: ret i32 1
+ __unaligned int a[10];
+ return __alignof__(a);
+}
+
+// -----------
+// structs
+// -----------
+typedef
+struct S1 {
+ char c;
+ int x;
+} S1;
+
+__unaligned S1 s1;
+void test20(void) {
+ // CHECK: {{%.*}} = load i32, i32* getelementptr inbounds (%struct.S1, %struct.S1* @s1, i32 0, i32 1), align 1
+ // CHECK: store i32 {{%.*}}, i32* getelementptr inbounds (%struct.S1, %struct.S1* @s1, i32 0, i32 1), align 1
+ s1.x++;
+}
+
+void test21(void) {
+ // CHECK: {{%.*}} = alloca %struct.S1, align 1
+ // CHECK: {{%.*}} = getelementptr inbounds %struct.S1, %struct.S1* {{%.*}}, i32 0, i32 1
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 1
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 1
+ __unaligned S1 s1_2;
+ s1_2.x++;
+}
+
+typedef
+struct __attribute__((packed)) S2 {
+ char c;
+ int x;
+} S2;
+
+__unaligned S2 s2;
+void test22(void) {
+ // CHECK: {{%.*}} = load i32, i32* getelementptr inbounds (%struct.S2, %struct.S2* @s2, i32 0, i32 1), align 1
+ // CHECK: store i32 {{%.*}}, i32* getelementptr inbounds (%struct.S2, %struct.S2* @s2, i32 0, i32 1), align 1
+ s2.x++;
+}
+
+void test23(void) {
+ // CHECK: {{%.*}} = alloca %struct.S2, align 1
+ // CHECK: {{%.*}} = getelementptr inbounds %struct.S2, %struct.S2* {{%.*}}, i32 0, i32 1
+ // CHECK: {{%.*}} = load i32, i32* {{%.*}}, align 1
+ // CHECK: store i32 {{%.*}}, i32* {{%.*}}, align 1
+ __unaligned S2 s2_2;
+ s2_2.x++;
+}
diff --git a/test/CodeGen/unaligned-field.c b/test/CodeGen/unaligned-field.c
new file mode 100644
index 000000000000..5aa59c279917
--- /dev/null
+++ b/test/CodeGen/unaligned-field.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fms-extensions -emit-llvm < %s | FileCheck %s
+// Test that __unaligned does not impact the layout of the fields.
+
+struct A
+{
+ char a;
+ __unaligned int b;
+} a;
+// CHECK: %struct.A = type { i8, i32 }
+
+struct A2
+{
+ int b;
+ char a;
+ __unaligned int c;
+} a2;
+// CHECK: %struct.A2 = type { i32, i8, i32 }
diff --git a/test/CodeGen/unsigned-promotion.c b/test/CodeGen/unsigned-promotion.c
index 4e7a4426a03e..4b13f68781b9 100644
--- a/test/CodeGen/unsigned-promotion.c
+++ b/test/CodeGen/unsigned-promotion.c
@@ -7,53 +7,6 @@
// RUN: -fsanitize=unsigned-integer-overflow | FileCheck %s --check-prefix=CHECKU
unsigned short si, sj, sk;
-unsigned char ci, cj, ck;
-
-extern void opaqueshort(unsigned short);
-extern void opaquechar(unsigned char);
-
-// CHECKS-LABEL: define void @testshortadd()
-// CHECKU-LABEL: define void @testshortadd()
-void testshortadd() {
- // CHECKS: load i16, i16* @sj
- // CHECKS: load i16, i16* @sk
- // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
- // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
- // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
- // CHECKS: call void @__ubsan_handle_add_overflow
- //
- // CHECKU: [[T1:%.*]] = load i16, i16* @sj
- // CHECKU: [[T2:%.*]] = zext i16 [[T1]]
- // CHECKU: [[T3:%.*]] = load i16, i16* @sk
- // CHECKU: [[T4:%.*]] = zext i16 [[T3]]
- // CHECKU-NOT: llvm.sadd
- // CHECKU-NOT: llvm.uadd
- // CHECKU: [[T5:%.*]] = add nsw i32 [[T2]], [[T4]]
-
- si = sj + sk;
-}
-
-// CHECKS-LABEL: define void @testshortsub()
-// CHECKU-LABEL: define void @testshortsub()
-void testshortsub() {
-
- // CHECKS: load i16, i16* @sj
- // CHECKS: load i16, i16* @sk
- // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
- // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
- // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
- // CHECKS: call void @__ubsan_handle_sub_overflow
- //
- // CHECKU: [[T1:%.*]] = load i16, i16* @sj
- // CHECKU: [[T2:%.*]] = zext i16 [[T1]]
- // CHECKU: [[T3:%.*]] = load i16, i16* @sk
- // CHECKU: [[T4:%.*]] = zext i16 [[T3]]
- // CHECKU-NOT: llvm.ssub
- // CHECKU-NOT: llvm.usub
- // CHECKU: [[T5:%.*]] = sub nsw i32 [[T2]], [[T4]]
-
- si = sj - sk;
-}
// CHECKS-LABEL: define void @testshortmul()
// CHECKU-LABEL: define void @testshortmul()
@@ -75,69 +28,3 @@ void testshortmul() {
// CHECKU: [[T5:%.*]] = mul nsw i32 [[T2]], [[T4]]
si = sj * sk;
}
-
-// CHECKS-LABEL: define void @testcharadd()
-// CHECKU-LABEL: define void @testcharadd()
-void testcharadd() {
-
- // CHECKS: load i8, i8* @cj
- // CHECKS: load i8, i8* @ck
- // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
- // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
- // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
- // CHECKS: call void @__ubsan_handle_add_overflow
- //
- // CHECKU: [[T1:%.*]] = load i8, i8* @cj
- // CHECKU: [[T2:%.*]] = zext i8 [[T1]]
- // CHECKU: [[T3:%.*]] = load i8, i8* @ck
- // CHECKU: [[T4:%.*]] = zext i8 [[T3]]
- // CHECKU-NOT: llvm.sadd
- // CHECKU-NOT: llvm.uadd
- // CHECKU: [[T5:%.*]] = add nsw i32 [[T2]], [[T4]]
-
- ci = cj + ck;
-}
-
-// CHECKS-LABEL: define void @testcharsub()
-// CHECKU-LABEL: define void @testcharsub()
-void testcharsub() {
-
- // CHECKS: load i8, i8* @cj
- // CHECKS: load i8, i8* @ck
- // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
- // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
- // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
- // CHECKS: call void @__ubsan_handle_sub_overflow
- //
- // CHECKU: [[T1:%.*]] = load i8, i8* @cj
- // CHECKU: [[T2:%.*]] = zext i8 [[T1]]
- // CHECKU: [[T3:%.*]] = load i8, i8* @ck
- // CHECKU: [[T4:%.*]] = zext i8 [[T3]]
- // CHECKU-NOT: llvm.ssub
- // CHECKU-NOT: llvm.usub
- // CHECKU: [[T5:%.*]] = sub nsw i32 [[T2]], [[T4]]
-
- ci = cj - ck;
-}
-
-// CHECKS-LABEL: define void @testcharmul()
-// CHECKU-LABEL: define void @testcharmul()
-void testcharmul() {
-
- // CHECKS: load i8, i8* @cj
- // CHECKS: load i8, i8* @ck
- // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
- // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
- // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
- // CHECKS: call void @__ubsan_handle_mul_overflow
- //
- // CHECKU: [[T1:%.*]] = load i8, i8* @cj
- // CHECKU: [[T2:%.*]] = zext i8 [[T1]]
- // CHECKU: [[T3:%.*]] = load i8, i8* @ck
- // CHECKU: [[T4:%.*]] = zext i8 [[T3]]
- // CHECKU-NOT: llvm.smul
- // CHECKU-NOT: llvm.umul
- // CHECKU: [[T5:%.*]] = mul nsw i32 [[T2]], [[T4]]
-
- ci = cj * ck;
-}
diff --git a/test/CodeGen/xop-builtins-cmp.c b/test/CodeGen/xop-builtins-cmp.c
new file mode 100644
index 000000000000..a805352ad3b9
--- /dev/null
+++ b/test/CodeGen/xop-builtins-cmp.c
@@ -0,0 +1,405 @@
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +xop -emit-llvm -o - -Wall -Werror | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +xop -fno-signed-char -emit-llvm -o - -Wall -Werror | FileCheck %s
+
+
+#include <x86intrin.h>
+
+// _MM_PCOMCTRL_LT
+
+__m128i test_mm_comlt_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comlt_epu8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomub(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 0)
+ return _mm_comlt_epu8(a, b);
+}
+
+__m128i test_mm_comlt_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comlt_epu16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomuw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 0)
+ return _mm_comlt_epu16(a, b);
+}
+
+__m128i test_mm_comlt_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comlt_epu32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomud(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 0)
+ return _mm_comlt_epu32(a, b);
+}
+
+__m128i test_mm_comlt_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comlt_epu64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomuq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 0)
+ return _mm_comlt_epu64(a, b);
+}
+
+__m128i test_mm_comlt_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comlt_epi8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 0)
+ return _mm_comlt_epi8(a, b);
+}
+
+__m128i test_mm_comlt_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comlt_epi16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 0)
+ return _mm_comlt_epi16(a, b);
+}
+
+__m128i test_mm_comlt_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comlt_epi32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomd(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 0)
+ return _mm_comlt_epi32(a, b);
+}
+
+__m128i test_mm_comlt_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comlt_epi64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 0)
+ return _mm_comlt_epi64(a, b);
+}
+
+// _MM_PCOMCTRL_LE
+
+__m128i test_mm_comle_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comle_epu8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomub(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 1)
+ return _mm_comle_epu8(a, b);
+}
+
+__m128i test_mm_comle_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comle_epu16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomuw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 1)
+ return _mm_comle_epu16(a, b);
+}
+
+__m128i test_mm_comle_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comle_epu32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomud(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 1)
+ return _mm_comle_epu32(a, b);
+}
+
+__m128i test_mm_comle_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comle_epu64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomuq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 1)
+ return _mm_comle_epu64(a, b);
+}
+
+__m128i test_mm_comle_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comle_epi8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 1)
+ return _mm_comle_epi8(a, b);
+}
+
+__m128i test_mm_comle_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comle_epi16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 1)
+ return _mm_comle_epi16(a, b);
+}
+
+__m128i test_mm_comle_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comle_epi32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomd(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 1)
+ return _mm_comle_epi32(a, b);
+}
+
+__m128i test_mm_comle_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comle_epi64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 1)
+ return _mm_comle_epi64(a, b);
+}
+
+// _MM_PCOMCTRL_GT
+
+__m128i test_mm_comgt_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comgt_epu8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomub(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 2)
+ return _mm_comgt_epu8(a, b);
+}
+
+__m128i test_mm_comgt_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comgt_epu16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomuw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 2)
+ return _mm_comgt_epu16(a, b);
+}
+
+__m128i test_mm_comgt_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comgt_epu32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomud(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 2)
+ return _mm_comgt_epu32(a, b);
+}
+
+__m128i test_mm_comgt_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comgt_epu64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomuq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 2)
+ return _mm_comgt_epu64(a, b);
+}
+
+__m128i test_mm_comgt_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comgt_epi8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 2)
+ return _mm_comgt_epi8(a, b);
+}
+
+__m128i test_mm_comgt_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comgt_epi16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 2)
+ return _mm_comgt_epi16(a, b);
+}
+
+__m128i test_mm_comgt_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comgt_epi32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomd(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 2)
+ return _mm_comgt_epi32(a, b);
+}
+
+__m128i test_mm_comgt_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comgt_epi64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 2)
+ return _mm_comgt_epi64(a, b);
+}
+
+// _MM_PCOMCTRL_GE
+
+__m128i test_mm_comge_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comge_epu8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomub(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 3)
+ return _mm_comge_epu8(a, b);
+}
+
+__m128i test_mm_comge_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comge_epu16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomuw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 3)
+ return _mm_comge_epu16(a, b);
+}
+
+__m128i test_mm_comge_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comge_epu32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomud(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 3)
+ return _mm_comge_epu32(a, b);
+}
+
+__m128i test_mm_comge_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comge_epu64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomuq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 3)
+ return _mm_comge_epu64(a, b);
+}
+
+__m128i test_mm_comge_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comge_epi8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 3)
+ return _mm_comge_epi8(a, b);
+}
+
+__m128i test_mm_comge_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comge_epi16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 3)
+ return _mm_comge_epi16(a, b);
+}
+
+__m128i test_mm_comge_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comge_epi32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomd(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 3)
+ return _mm_comge_epi32(a, b);
+}
+
+__m128i test_mm_comge_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comge_epi64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 3)
+ return _mm_comge_epi64(a, b);
+}
+
+// _MM_PCOMCTRL_EQ
+
+__m128i test_mm_comeq_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comeq_epu8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomub(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 4)
+ return _mm_comeq_epu8(a, b);
+}
+
+__m128i test_mm_comeq_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comeq_epu16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomuw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 4)
+ return _mm_comeq_epu16(a, b);
+}
+
+__m128i test_mm_comeq_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comeq_epu32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomud(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 4)
+ return _mm_comeq_epu32(a, b);
+}
+
+__m128i test_mm_comeq_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comeq_epu64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomuq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 4)
+ return _mm_comeq_epu64(a, b);
+}
+
+__m128i test_mm_comeq_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comeq_epi8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 4)
+ return _mm_comeq_epi8(a, b);
+}
+
+__m128i test_mm_comeq_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comeq_epi16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 4)
+ return _mm_comeq_epi16(a, b);
+}
+
+__m128i test_mm_comeq_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comeq_epi32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomd(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 4)
+ return _mm_comeq_epi32(a, b);
+}
+
+__m128i test_mm_comeq_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comeq_epi64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 4)
+ return _mm_comeq_epi64(a, b);
+}
+
+// _MM_PCOMCTRL_NEQ
+
+__m128i test_mm_comneq_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comneq_epu8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomub(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 5)
+ return _mm_comneq_epu8(a, b);
+}
+
+__m128i test_mm_comneq_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comneq_epu16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomuw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 5)
+ return _mm_comneq_epu16(a, b);
+}
+
+__m128i test_mm_comneq_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comneq_epu32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomud(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 5)
+ return _mm_comneq_epu32(a, b);
+}
+
+__m128i test_mm_comneq_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comneq_epu64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomuq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 5)
+ return _mm_comneq_epu64(a, b);
+}
+
+__m128i test_mm_comneq_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comneq_epi8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 5)
+ return _mm_comneq_epi8(a, b);
+}
+
+__m128i test_mm_comneq_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comneq_epi16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 5)
+ return _mm_comneq_epi16(a, b);
+}
+
+__m128i test_mm_comneq_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comneq_epi32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomd(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 5)
+ return _mm_comneq_epi32(a, b);
+}
+
+__m128i test_mm_comneq_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comneq_epi64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 5)
+ return _mm_comneq_epi64(a, b);
+}
+
+// _MM_PCOMCTRL_FALSE
+
+__m128i test_mm_comfalse_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comfalse_epu8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomub(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 6)
+ return _mm_comfalse_epu8(a, b);
+}
+
+__m128i test_mm_comfalse_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comfalse_epu16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomuw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 6)
+ return _mm_comfalse_epu16(a, b);
+}
+
+__m128i test_mm_comfalse_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comfalse_epu32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomud(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 6)
+ return _mm_comfalse_epu32(a, b);
+}
+
+__m128i test_mm_comfalse_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comfalse_epu64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomuq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 6)
+ return _mm_comfalse_epu64(a, b);
+}
+
+__m128i test_mm_comfalse_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comfalse_epi8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 6)
+ return _mm_comfalse_epi8(a, b);
+}
+
+__m128i test_mm_comfalse_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comfalse_epi16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 6)
+ return _mm_comfalse_epi16(a, b);
+}
+
+__m128i test_mm_comfalse_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comfalse_epi32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomd(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 6)
+ return _mm_comfalse_epi32(a, b);
+}
+
+__m128i test_mm_comfalse_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comfalse_epi64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 6)
+ return _mm_comfalse_epi64(a, b);
+}
+
+// _MM_PCOMCTRL_TRUE
+
+__m128i test_mm_comtrue_epu8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comtrue_epu8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomub(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 7)
+ return _mm_comtrue_epu8(a, b);
+}
+
+__m128i test_mm_comtrue_epu16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comtrue_epu16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomuw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 7)
+ return _mm_comtrue_epu16(a, b);
+}
+
+__m128i test_mm_comtrue_epu32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comtrue_epu32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomud(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 7)
+ return _mm_comtrue_epu32(a, b);
+}
+
+__m128i test_mm_comtrue_epu64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comtrue_epu64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomuq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 7)
+ return _mm_comtrue_epu64(a, b);
+}
+
+__m128i test_mm_comtrue_epi8(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comtrue_epi8
+ // CHECK: call <16 x i8> @llvm.x86.xop.vpcomb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i8 7)
+ return _mm_comtrue_epi8(a, b);
+}
+
+__m128i test_mm_comtrue_epi16(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comtrue_epi16
+ // CHECK: call <8 x i16> @llvm.x86.xop.vpcomw(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, i8 7)
+ return _mm_comtrue_epi16(a, b);
+}
+
+__m128i test_mm_comtrue_epi32(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comtrue_epi32
+ // CHECK: call <4 x i32> @llvm.x86.xop.vpcomd(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, i8 7)
+ return _mm_comtrue_epi32(a, b);
+}
+
+__m128i test_mm_comtrue_epi64(__m128i a, __m128i b) {
+ // CHECK-LABEL: test_mm_comtrue_epi64
+ // CHECK: call <2 x i64> @llvm.x86.xop.vpcomq(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, i8 7)
+ return _mm_comtrue_epi64(a, b);
+}
diff --git a/test/CodeGen/xop-builtins.c b/test/CodeGen/xop-builtins.c
index da9a3b925de2..5302b9ab8f2f 100644
--- a/test/CodeGen/xop-builtins.c
+++ b/test/CodeGen/xop-builtins.c
@@ -170,13 +170,19 @@ __m128i test_mm_hsubq_epi32(__m128i a) {
__m128i test_mm_cmov_si128(__m128i a, __m128i b, __m128i c) {
// CHECK-LABEL: test_mm_cmov_si128
- // CHECK: call <2 x i64> @llvm.x86.xop.vpcmov(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}})
+ // CHECK: [[AND:%.*]] = and <2 x i64> %{{.*}}, %{{.*}}
+ // CHECK: [[NEG:%.*]] = xor <2 x i64> %{{.*}}, <i64 -1, i64 -1>
+ // CHECK-NEXT: [[ANDN:%.*]] = and <2 x i64> %{{.*}}, [[NEG]]
+ // CHECK-NEXT: %{{.*}} = or <2 x i64> [[AND]], [[ANDN]]
return _mm_cmov_si128(a, b, c);
}
__m256i test_mm256_cmov_si256(__m256i a, __m256i b, __m256i c) {
// CHECK-LABEL: test_mm256_cmov_si256
- // CHECK: call <4 x i64> @llvm.x86.xop.vpcmov.256(<4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}})
+ // CHECK: [[AND:%.*]] = and <4 x i64> %{{.*}}, %{{.*}}
+ // CHECK: [[NEG:%.*]] = xor <4 x i64> %{{.*}}, <i64 -1, i64 -1, i64 -1, i64 -1>
+ // CHECK-NEXT: [[ANDN:%.*]] = and <4 x i64> %{{.*}}, [[NEG]]
+ // CHECK-NEXT: %{{.*}} = or <4 x i64> [[AND]], [[ANDN]]
return _mm256_cmov_si256(a, b, c);
}
diff --git a/test/CodeGen/xray-always-instrument.cpp b/test/CodeGen/xray-always-instrument.cpp
new file mode 100644
index 000000000000..60d859569958
--- /dev/null
+++ b/test/CodeGen/xray-always-instrument.cpp
@@ -0,0 +1,15 @@
+// RUN: echo "fun:*foo*" > %t.always-instrument
+// RUN: echo "src:*xray-always-instrument.cpp" >> %t.always-instrument
+// RUN: %clang_cc1 -fxray-instrument -x c++ -std=c++11 -fxray-always-instrument=%t.always-instrument -emit-llvm -o - %s -triple x86_64-unknown-linux-gnu | FileCheck %s
+
+void foo() {}
+
+[[clang::xray_never_instrument]] void bar() {}
+
+void baz() {}
+
+// CHECK: define void @_Z3foov() #[[ALWAYSATTR:[0-9]+]] {
+// CHECK: define void @_Z3barv() #[[NEVERATTR:[0-9]+]] {
+// CHECK: define void @_Z3bazv() #[[ALWAYSATTR:[0-9]+]] {
+// CHECK: attributes #[[ALWAYSATTR]] = {{.*}} "function-instrument"="xray-always" {{.*}}
+// CHECK: attributes #[[NEVERATTR]] = {{.*}} "function-instrument"="xray-never" {{.*}}
diff --git a/test/CodeGen/xray-attributes-supported-arm.cpp b/test/CodeGen/xray-attributes-supported-arm.cpp
deleted file mode 100644
index 3104f285bfb3..000000000000
--- a/test/CodeGen/xray-attributes-supported-arm.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple arm-unknown-linux-gnu | FileCheck %s
-
-// Make sure that the LLVM attribute for XRay-annotated functions do show up.
-[[clang::xray_always_instrument]] void foo() {
-// CHECK: define void @_Z3foov() #0
-};
-
-[[clang::xray_never_instrument]] void bar() {
-// CHECK: define void @_Z3barv() #1
-};
-
-// CHECK: #0 = {{.*}}"function-instrument"="xray-always"
-// CHECK: #1 = {{.*}}"function-instrument"="xray-never"
diff --git a/test/CodeGen/xray-attributes-supported.cpp b/test/CodeGen/xray-attributes-supported.cpp
index d70b3aa26013..860efb276f69 100644
--- a/test/CodeGen/xray-attributes-supported.cpp
+++ b/test/CodeGen/xray-attributes-supported.cpp
@@ -1,4 +1,10 @@
// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple x86_64-unknown-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple arm-unknown-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple mips-unknown-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple mipsel-unknown-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple mips64-unknown-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple mips64el-unknown-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple powerpc64le-unknown-linux-gnu | FileCheck %s
// Make sure that the LLVM attribute for XRay-annotated functions do show up.
[[clang::xray_always_instrument]] void foo() {
diff --git a/test/CodeGen/xray-instruction-threshold.cpp b/test/CodeGen/xray-instruction-threshold.cpp
new file mode 100644
index 000000000000..b5f4489bd97e
--- /dev/null
+++ b/test/CodeGen/xray-instruction-threshold.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fxray-instrument -fxray-instruction-threshold=1 -x c++ -std=c++11 -emit-llvm -o - %s -triple x86_64-unknown-linux-gnu | FileCheck %s
+
+int foo() {
+ return 1;
+}
+
+[[clang::xray_never_instrument]] int bar() {
+ return 2;
+}
+
+// CHECK: define i32 @_Z3foov() #[[THRESHOLD:[0-9]+]] {
+// CHECK: define i32 @_Z3barv() #[[NEVERATTR:[0-9]+]] {
+// CHECK-DAG: attributes #[[THRESHOLD]] = {{.*}} "xray-instruction-threshold"="1" {{.*}}
+// CHECK-DAG: attributes #[[NEVERATTR]] = {{.*}} "function-instrument"="xray-never" {{.*}}
diff --git a/test/CodeGen/xray-log-args.cpp b/test/CodeGen/xray-log-args.cpp
new file mode 100644
index 000000000000..d4f4a1ba851b
--- /dev/null
+++ b/test/CodeGen/xray-log-args.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -fxray-instrument -std=c++11 -x c++ -emit-llvm -o - -triple x86_64-unknown-linux-gnu | FileCheck %s
+
+// Make sure that the LLVM attribute for XRay-annotated functions do show up.
+[[clang::xray_always_instrument,clang::xray_log_args(1)]] void foo(int a) {
+// CHECK: define void @_Z3fooi(i32 %a) #0
+};
+
+[[clang::xray_log_args(1)]] void bar(int a) {
+// CHECK: define void @_Z3bari(i32 %a) #1
+};
+
+// CHECK: #0 = {{.*}}"function-instrument"="xray-always"{{.*}}"xray-log-args"="1"
+// CHECK-NOT: #1 = {{.*}}"xray-log-args"="1"
diff --git a/test/CodeGen/zvector.c b/test/CodeGen/zvector.c
index ebe7e415e1db..a8405a78e92b 100644
--- a/test/CodeGen/zvector.c
+++ b/test/CodeGen/zvector.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z13 -fzvector \
-// RUN: -O -emit-llvm -o - -W -Wall -Werror %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z13 -fzvector -emit-llvm -o - -W -Wall -Werror %s | opt -S -mem2reg | FileCheck %s
volatile vector signed char sc, sc2;
volatile vector unsigned char uc, uc2;
@@ -21,2778 +20,3349 @@ volatile vector double fd, fd2;
volatile int cnt;
-void test_assign (void)
-{
-// CHECK-LABEL: test_assign
+// CHECK-LABEL: define void @test_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: store volatile <16 x i8> [[TMP0]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: store volatile <16 x i8> [[TMP1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: store volatile <8 x i16> [[TMP2]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: store volatile <8 x i16> [[TMP3]], <8 x i16>* @us, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: store volatile <4 x i32> [[TMP4]], <4 x i32>* @si, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: store volatile <4 x i32> [[TMP5]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: store volatile <2 x i64> [[TMP6]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: store volatile <2 x i64> [[TMP7]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: store volatile <2 x double> [[TMP8]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_assign(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: store volatile <16 x i8> [[VAL]], <16 x i8>* @sc
sc = sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: store volatile <16 x i8> [[VAL]], <16 x i8>* @uc
uc = uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: store volatile <8 x i16> [[VAL]], <8 x i16>* @ss
ss = ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: store volatile <8 x i16> [[VAL]], <8 x i16>* @us
us = us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: store volatile <4 x i32> [[VAL]], <4 x i32>* @si
si = si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: store volatile <4 x i32> [[VAL]], <4 x i32>* @ui
ui = ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: store volatile <2 x i64> [[VAL]], <2 x i64>* @sl
sl = sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: store volatile <2 x i64> [[VAL]], <2 x i64>* @ul
ul = ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: store volatile <2 x double> [[VAL]], <2 x double>* @fd
fd = fd2;
}
-void test_pos (void)
-{
-// CHECK-LABEL: test_pos
+// CHECK-LABEL: define void @test_pos() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: store volatile <16 x i8> [[TMP0]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: store volatile <16 x i8> [[TMP1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: store volatile <8 x i16> [[TMP2]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: store volatile <8 x i16> [[TMP3]], <8 x i16>* @us, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: store volatile <4 x i32> [[TMP4]], <4 x i32>* @si, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: store volatile <4 x i32> [[TMP5]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: store volatile <2 x i64> [[TMP6]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: store volatile <2 x i64> [[TMP7]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: store volatile <2 x double> [[TMP8]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_pos(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: store volatile <16 x i8> [[VAL]], <16 x i8>* @sc
sc = +sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: store volatile <16 x i8> [[VAL]], <16 x i8>* @uc
uc = +uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: store volatile <8 x i16> [[VAL]], <8 x i16>* @ss
ss = +ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: store volatile <8 x i16> [[VAL]], <8 x i16>* @us
us = +us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: store volatile <4 x i32> [[VAL]], <4 x i32>* @si
si = +si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: store volatile <4 x i32> [[VAL]], <4 x i32>* @ui
ui = +ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: store volatile <2 x i64> [[VAL]], <2 x i64>* @sl
sl = +sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: store volatile <2 x i64> [[VAL]], <2 x i64>* @ul
ul = +ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: store volatile <2 x double> [[VAL]], <2 x double>* @fd
fd = +fd2;
}
-void test_neg (void)
-{
-// CHECK-LABEL: test_neg
+// CHECK-LABEL: define void @test_neg() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[SUB:%.*]] = sub <16 x i8> zeroinitializer, [[TMP0]]
+// CHECK: store volatile <16 x i8> [[SUB]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[SUB1:%.*]] = sub <8 x i16> zeroinitializer, [[TMP1]]
+// CHECK: store volatile <8 x i16> [[SUB1]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[SUB2:%.*]] = sub <4 x i32> zeroinitializer, [[TMP2]]
+// CHECK: store volatile <4 x i32> [[SUB2]], <4 x i32>* @si, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[SUB3:%.*]] = sub <2 x i64> zeroinitializer, [[TMP3]]
+// CHECK: store volatile <2 x i64> [[SUB3]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[SUB4:%.*]] = fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[TMP4]]
+// CHECK: store volatile <2 x double> [[SUB4]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_neg(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = sub <16 x i8> zeroinitializer, [[VAL]]
sc = -sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = sub <8 x i16> zeroinitializer, [[VAL]]
ss = -ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = sub <4 x i32> zeroinitializer, [[VAL]]
si = -si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = sub <2 x i64> zeroinitializer, [[VAL]]
sl = -sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[VAL]]
fd = -fd2;
}
-void test_preinc (void)
-{
-// CHECK-LABEL: test_preinc
+// CHECK-LABEL: define void @test_preinc() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[INC:%.*]] = add <16 x i8> [[TMP0]], <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
+// CHECK: store volatile <16 x i8> [[INC]], <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[INC1:%.*]] = add <16 x i8> [[TMP1]], <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
+// CHECK: store volatile <16 x i8> [[INC1]], <16 x i8>* @uc2, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[INC2:%.*]] = add <8 x i16> [[TMP2]], <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+// CHECK: store volatile <8 x i16> [[INC2]], <8 x i16>* @ss2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[INC3:%.*]] = add <8 x i16> [[TMP3]], <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+// CHECK: store volatile <8 x i16> [[INC3]], <8 x i16>* @us2, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[INC4:%.*]] = add <4 x i32> [[TMP4]], <i32 1, i32 1, i32 1, i32 1>
+// CHECK: store volatile <4 x i32> [[INC4]], <4 x i32>* @si2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[INC5:%.*]] = add <4 x i32> [[TMP5]], <i32 1, i32 1, i32 1, i32 1>
+// CHECK: store volatile <4 x i32> [[INC5]], <4 x i32>* @ui2, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[INC6:%.*]] = add <2 x i64> [[TMP6]], <i64 1, i64 1>
+// CHECK: store volatile <2 x i64> [[INC6]], <2 x i64>* @sl2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[INC7:%.*]] = add <2 x i64> [[TMP7]], <i64 1, i64 1>
+// CHECK: store volatile <2 x i64> [[INC7]], <2 x i64>* @ul2, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[INC8:%.*]] = fadd <2 x double> [[TMP8]], <double 1.000000e+00, double 1.000000e+00>
+// CHECK: store volatile <2 x double> [[INC8]], <2 x double>* @fd2, align 8
+// CHECK: ret void
+void test_preinc(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL]], <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
++sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL]], <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
++uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL]], <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
++ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL]], <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
++us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL]], <i32 1, i32 1, i32 1, i32 1>
++si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL]], <i32 1, i32 1, i32 1, i32 1>
++ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL]], <i64 1, i64 1>
++sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL]], <i64 1, i64 1>
++ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fadd <2 x double> [[VAL]], <double 1.000000e+00, double 1.000000e+00>
++fd2;
}
-void test_postinc (void)
-{
-// CHECK-LABEL: test_postinc
+// CHECK-LABEL: define void @test_postinc() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[INC:%.*]] = add <16 x i8> [[TMP0]], <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
+// CHECK: store volatile <16 x i8> [[INC]], <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[INC1:%.*]] = add <16 x i8> [[TMP1]], <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
+// CHECK: store volatile <16 x i8> [[INC1]], <16 x i8>* @uc2, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[INC2:%.*]] = add <8 x i16> [[TMP2]], <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+// CHECK: store volatile <8 x i16> [[INC2]], <8 x i16>* @ss2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[INC3:%.*]] = add <8 x i16> [[TMP3]], <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+// CHECK: store volatile <8 x i16> [[INC3]], <8 x i16>* @us2, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[INC4:%.*]] = add <4 x i32> [[TMP4]], <i32 1, i32 1, i32 1, i32 1>
+// CHECK: store volatile <4 x i32> [[INC4]], <4 x i32>* @si2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[INC5:%.*]] = add <4 x i32> [[TMP5]], <i32 1, i32 1, i32 1, i32 1>
+// CHECK: store volatile <4 x i32> [[INC5]], <4 x i32>* @ui2, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[INC6:%.*]] = add <2 x i64> [[TMP6]], <i64 1, i64 1>
+// CHECK: store volatile <2 x i64> [[INC6]], <2 x i64>* @sl2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[INC7:%.*]] = add <2 x i64> [[TMP7]], <i64 1, i64 1>
+// CHECK: store volatile <2 x i64> [[INC7]], <2 x i64>* @ul2, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[INC8:%.*]] = fadd <2 x double> [[TMP8]], <double 1.000000e+00, double 1.000000e+00>
+// CHECK: store volatile <2 x double> [[INC8]], <2 x double>* @fd2, align 8
+// CHECK: ret void
+void test_postinc(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL]], <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
sc2++;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL]], <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
uc2++;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL]], <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
ss2++;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL]], <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
us2++;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL]], <i32 1, i32 1, i32 1, i32 1>
si2++;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL]], <i32 1, i32 1, i32 1, i32 1>
ui2++;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL]], <i64 1, i64 1>
sl2++;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL]], <i64 1, i64 1>
ul2++;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fadd <2 x double> [[VAL]], <double 1.000000e+00, double 1.000000e+00>
fd2++;
}
-void test_predec (void)
-{
-// CHECK-LABEL: test_predec
+// CHECK-LABEL: define void @test_predec() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[DEC:%.*]] = add <16 x i8> [[TMP0]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
+// CHECK: store volatile <16 x i8> [[DEC]], <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[DEC1:%.*]] = add <16 x i8> [[TMP1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
+// CHECK: store volatile <16 x i8> [[DEC1]], <16 x i8>* @uc2, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[DEC2:%.*]] = add <8 x i16> [[TMP2]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: store volatile <8 x i16> [[DEC2]], <8 x i16>* @ss2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[DEC3:%.*]] = add <8 x i16> [[TMP3]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: store volatile <8 x i16> [[DEC3]], <8 x i16>* @us2, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[DEC4:%.*]] = add <4 x i32> [[TMP4]], <i32 -1, i32 -1, i32 -1, i32 -1>
+// CHECK: store volatile <4 x i32> [[DEC4]], <4 x i32>* @si2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[DEC5:%.*]] = add <4 x i32> [[TMP5]], <i32 -1, i32 -1, i32 -1, i32 -1>
+// CHECK: store volatile <4 x i32> [[DEC5]], <4 x i32>* @ui2, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[DEC6:%.*]] = add <2 x i64> [[TMP6]], <i64 -1, i64 -1>
+// CHECK: store volatile <2 x i64> [[DEC6]], <2 x i64>* @sl2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[DEC7:%.*]] = add <2 x i64> [[TMP7]], <i64 -1, i64 -1>
+// CHECK: store volatile <2 x i64> [[DEC7]], <2 x i64>* @ul2, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[DEC8:%.*]] = fadd <2 x double> [[TMP8]], <double -1.000000e+00, double -1.000000e+00>
+// CHECK: store volatile <2 x double> [[DEC8]], <2 x double>* @fd2, align 8
+// CHECK: ret void
+void test_predec(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
--sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
--uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
--ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
--us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL]], <i32 -1, i32 -1, i32 -1, i32 -1>
--si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL]], <i32 -1, i32 -1, i32 -1, i32 -1>
--ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL]], <i64 -1, i64 -1>
--sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL]], <i64 -1, i64 -1>
--ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fadd <2 x double> [[VAL]], <double -1.000000e+00, double -1.000000e+00>
--fd2;
}
-void test_postdec (void)
-{
-// CHECK-LABEL: test_postdec
+// CHECK-LABEL: define void @test_postdec() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[DEC:%.*]] = add <16 x i8> [[TMP0]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
+// CHECK: store volatile <16 x i8> [[DEC]], <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[DEC1:%.*]] = add <16 x i8> [[TMP1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
+// CHECK: store volatile <16 x i8> [[DEC1]], <16 x i8>* @uc2, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[DEC2:%.*]] = add <8 x i16> [[TMP2]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: store volatile <8 x i16> [[DEC2]], <8 x i16>* @ss2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[DEC3:%.*]] = add <8 x i16> [[TMP3]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: store volatile <8 x i16> [[DEC3]], <8 x i16>* @us2, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[DEC4:%.*]] = add <4 x i32> [[TMP4]], <i32 -1, i32 -1, i32 -1, i32 -1>
+// CHECK: store volatile <4 x i32> [[DEC4]], <4 x i32>* @si2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[DEC5:%.*]] = add <4 x i32> [[TMP5]], <i32 -1, i32 -1, i32 -1, i32 -1>
+// CHECK: store volatile <4 x i32> [[DEC5]], <4 x i32>* @ui2, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[DEC6:%.*]] = add <2 x i64> [[TMP6]], <i64 -1, i64 -1>
+// CHECK: store volatile <2 x i64> [[DEC6]], <2 x i64>* @sl2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[DEC7:%.*]] = add <2 x i64> [[TMP7]], <i64 -1, i64 -1>
+// CHECK: store volatile <2 x i64> [[DEC7]], <2 x i64>* @ul2, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[DEC8:%.*]] = fadd <2 x double> [[TMP8]], <double -1.000000e+00, double -1.000000e+00>
+// CHECK: store volatile <2 x double> [[DEC8]], <2 x double>* @fd2, align 8
+// CHECK: ret void
+void test_postdec(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
sc2--;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
uc2--;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
ss2--;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
us2--;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL]], <i32 -1, i32 -1, i32 -1, i32 -1>
si2--;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL]], <i32 -1, i32 -1, i32 -1, i32 -1>
ui2--;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL]], <i64 -1, i64 -1>
sl2--;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL]], <i64 -1, i64 -1>
ul2--;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fadd <2 x double> [[VAL]], <double -1.000000e+00, double -1.000000e+00>
fd2--;
}
-void test_add (void)
-{
-// CHECK-LABEL: test_add
+// CHECK-LABEL: define void @test_add() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[ADD:%.*]] = add <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[ADD]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[ADD1:%.*]] = add <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[ADD1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[ADD2:%.*]] = add <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: store volatile <16 x i8> [[ADD2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[ADD3:%.*]] = add <16 x i8> [[TMP6]], [[TMP7]]
+// CHECK: store volatile <16 x i8> [[ADD3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[ADD4:%.*]] = add <16 x i8> [[TMP8]], [[TMP9]]
+// CHECK: store volatile <16 x i8> [[ADD4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[ADD5:%.*]] = add <16 x i8> [[TMP10]], [[TMP11]]
+// CHECK: store volatile <16 x i8> [[ADD5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[ADD6:%.*]] = add <8 x i16> [[TMP12]], [[TMP13]]
+// CHECK: store volatile <8 x i16> [[ADD6]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[ADD7:%.*]] = add <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <8 x i16> [[ADD7]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[ADD8:%.*]] = add <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <8 x i16> [[ADD8]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[ADD9:%.*]] = add <8 x i16> [[TMP18]], [[TMP19]]
+// CHECK: store volatile <8 x i16> [[ADD9]], <8 x i16>* @us, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[ADD10:%.*]] = add <8 x i16> [[TMP20]], [[TMP21]]
+// CHECK: store volatile <8 x i16> [[ADD10]], <8 x i16>* @us, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[ADD11:%.*]] = add <8 x i16> [[TMP22]], [[TMP23]]
+// CHECK: store volatile <8 x i16> [[ADD11]], <8 x i16>* @us, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[ADD12:%.*]] = add <4 x i32> [[TMP24]], [[TMP25]]
+// CHECK: store volatile <4 x i32> [[ADD12]], <4 x i32>* @si, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[ADD13:%.*]] = add <4 x i32> [[TMP26]], [[TMP27]]
+// CHECK: store volatile <4 x i32> [[ADD13]], <4 x i32>* @si, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[ADD14:%.*]] = add <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: store volatile <4 x i32> [[ADD14]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[ADD15:%.*]] = add <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: store volatile <4 x i32> [[ADD15]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[ADD16:%.*]] = add <4 x i32> [[TMP32]], [[TMP33]]
+// CHECK: store volatile <4 x i32> [[ADD16]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[ADD17:%.*]] = add <4 x i32> [[TMP34]], [[TMP35]]
+// CHECK: store volatile <4 x i32> [[ADD17]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[ADD18:%.*]] = add <2 x i64> [[TMP36]], [[TMP37]]
+// CHECK: store volatile <2 x i64> [[ADD18]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[ADD19:%.*]] = add <2 x i64> [[TMP38]], [[TMP39]]
+// CHECK: store volatile <2 x i64> [[ADD19]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP40:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[ADD20:%.*]] = add <2 x i64> [[TMP40]], [[TMP41]]
+// CHECK: store volatile <2 x i64> [[ADD20]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[ADD21:%.*]] = add <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: store volatile <2 x i64> [[ADD21]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[ADD22:%.*]] = add <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: store volatile <2 x i64> [[ADD22]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[ADD23:%.*]] = add <2 x i64> [[TMP46]], [[TMP47]]
+// CHECK: store volatile <2 x i64> [[ADD23]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[ADD24:%.*]] = fadd <2 x double> [[TMP48]], [[TMP49]]
+// CHECK: store volatile <2 x double> [[ADD24]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_add(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL2]], [[VAL1]]
sc = sc + sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL2]], [[VAL1]]
sc = sc + bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL2]], [[VAL1]]
sc = bc + sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL2]], [[VAL1]]
uc = uc + uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL2]], [[VAL1]]
uc = uc + bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = add <16 x i8> [[VAL2]], [[VAL1]]
uc = bc + uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL2]], [[VAL1]]
ss = ss + ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL2]], [[VAL1]]
ss = ss + bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL2]], [[VAL1]]
ss = bs + ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL2]], [[VAL1]]
us = us + us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL2]], [[VAL1]]
us = us + bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = add <8 x i16> [[VAL2]], [[VAL1]]
us = bs + us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL2]], [[VAL1]]
si = si + si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL2]], [[VAL1]]
si = si + bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL2]], [[VAL1]]
si = bi + si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL2]], [[VAL1]]
ui = ui + ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL2]], [[VAL1]]
ui = ui + bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = add <4 x i32> [[VAL2]], [[VAL1]]
ui = bi + ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL2]], [[VAL1]]
sl = sl + sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL2]], [[VAL1]]
sl = sl + bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL2]], [[VAL1]]
sl = bl + sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL2]], [[VAL1]]
ul = ul + ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL2]], [[VAL1]]
ul = ul + bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = add <2 x i64> [[VAL2]], [[VAL1]]
ul = bl + ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fadd <2 x double> [[VAL1]], [[VAL2]]
fd = fd + fd2;
}
-void test_add_assign (void)
-{
-// CHECK-LABEL: test_add_assign
+// CHECK-LABEL: define void @test_add_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[ADD:%.*]] = add <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[ADD]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[ADD1:%.*]] = add <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[ADD1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[ADD2:%.*]] = add <16 x i8> [[TMP5]], [[TMP4]]
+// CHECK: store volatile <16 x i8> [[ADD2]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[ADD3:%.*]] = add <16 x i8> [[TMP7]], [[TMP6]]
+// CHECK: store volatile <16 x i8> [[ADD3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[ADD4:%.*]] = add <8 x i16> [[TMP9]], [[TMP8]]
+// CHECK: store volatile <8 x i16> [[ADD4]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[ADD5:%.*]] = add <8 x i16> [[TMP11]], [[TMP10]]
+// CHECK: store volatile <8 x i16> [[ADD5]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[ADD6:%.*]] = add <8 x i16> [[TMP13]], [[TMP12]]
+// CHECK: store volatile <8 x i16> [[ADD6]], <8 x i16>* @us, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[ADD7:%.*]] = add <8 x i16> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <8 x i16> [[ADD7]], <8 x i16>* @us, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[ADD8:%.*]] = add <4 x i32> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <4 x i32> [[ADD8]], <4 x i32>* @si, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[ADD9:%.*]] = add <4 x i32> [[TMP19]], [[TMP18]]
+// CHECK: store volatile <4 x i32> [[ADD9]], <4 x i32>* @si, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[ADD10:%.*]] = add <4 x i32> [[TMP21]], [[TMP20]]
+// CHECK: store volatile <4 x i32> [[ADD10]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[ADD11:%.*]] = add <4 x i32> [[TMP23]], [[TMP22]]
+// CHECK: store volatile <4 x i32> [[ADD11]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[ADD12:%.*]] = add <2 x i64> [[TMP25]], [[TMP24]]
+// CHECK: store volatile <2 x i64> [[ADD12]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[ADD13:%.*]] = add <2 x i64> [[TMP27]], [[TMP26]]
+// CHECK: store volatile <2 x i64> [[ADD13]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[ADD14:%.*]] = add <2 x i64> [[TMP29]], [[TMP28]]
+// CHECK: store volatile <2 x i64> [[ADD14]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[ADD15:%.*]] = add <2 x i64> [[TMP31]], [[TMP30]]
+// CHECK: store volatile <2 x i64> [[ADD15]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[ADD16:%.*]] = fadd <2 x double> [[TMP33]], [[TMP32]]
+// CHECK: store volatile <2 x double> [[ADD16]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_add_assign(void) {
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = add <16 x i8> [[VAL1]], [[VAL2]]
sc += sc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = add <16 x i8> [[VAL1]], [[VAL2]]
sc += bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = add <16 x i8> [[VAL1]], [[VAL2]]
uc += uc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = add <16 x i8> [[VAL1]], [[VAL2]]
uc += bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = add <8 x i16> [[VAL1]], [[VAL2]]
ss += ss2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = add <8 x i16> [[VAL1]], [[VAL2]]
ss += bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = add <8 x i16> [[VAL1]], [[VAL2]]
us += us2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = add <8 x i16> [[VAL1]], [[VAL2]]
us += bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = add <4 x i32> [[VAL1]], [[VAL2]]
si += si2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = add <4 x i32> [[VAL1]], [[VAL2]]
si += bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = add <4 x i32> [[VAL1]], [[VAL2]]
ui += ui2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = add <4 x i32> [[VAL1]], [[VAL2]]
ui += bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = add <2 x i64> [[VAL1]], [[VAL2]]
sl += sl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = add <2 x i64> [[VAL1]], [[VAL2]]
sl += bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = add <2 x i64> [[VAL1]], [[VAL2]]
ul += ul2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = add <2 x i64> [[VAL1]], [[VAL2]]
ul += bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: %{{.*}} = fadd <2 x double> [[VAL2]], [[VAL1]]
fd += fd2;
}
-void test_sub (void)
-{
-// CHECK-LABEL: test_sub
+// CHECK-LABEL: define void @test_sub() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[SUB:%.*]] = sub <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[SUB]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[SUB1:%.*]] = sub <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[SUB1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[SUB2:%.*]] = sub <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: store volatile <16 x i8> [[SUB2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[SUB3:%.*]] = sub <16 x i8> [[TMP6]], [[TMP7]]
+// CHECK: store volatile <16 x i8> [[SUB3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[SUB4:%.*]] = sub <16 x i8> [[TMP8]], [[TMP9]]
+// CHECK: store volatile <16 x i8> [[SUB4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[SUB5:%.*]] = sub <16 x i8> [[TMP10]], [[TMP11]]
+// CHECK: store volatile <16 x i8> [[SUB5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[SUB6:%.*]] = sub <8 x i16> [[TMP12]], [[TMP13]]
+// CHECK: store volatile <8 x i16> [[SUB6]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[SUB7:%.*]] = sub <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <8 x i16> [[SUB7]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[SUB8:%.*]] = sub <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <8 x i16> [[SUB8]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[SUB9:%.*]] = sub <8 x i16> [[TMP18]], [[TMP19]]
+// CHECK: store volatile <8 x i16> [[SUB9]], <8 x i16>* @us, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[SUB10:%.*]] = sub <8 x i16> [[TMP20]], [[TMP21]]
+// CHECK: store volatile <8 x i16> [[SUB10]], <8 x i16>* @us, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[SUB11:%.*]] = sub <8 x i16> [[TMP22]], [[TMP23]]
+// CHECK: store volatile <8 x i16> [[SUB11]], <8 x i16>* @us, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[SUB12:%.*]] = sub <4 x i32> [[TMP24]], [[TMP25]]
+// CHECK: store volatile <4 x i32> [[SUB12]], <4 x i32>* @si, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[SUB13:%.*]] = sub <4 x i32> [[TMP26]], [[TMP27]]
+// CHECK: store volatile <4 x i32> [[SUB13]], <4 x i32>* @si, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[SUB14:%.*]] = sub <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: store volatile <4 x i32> [[SUB14]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[SUB15:%.*]] = sub <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: store volatile <4 x i32> [[SUB15]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[SUB16:%.*]] = sub <4 x i32> [[TMP32]], [[TMP33]]
+// CHECK: store volatile <4 x i32> [[SUB16]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[SUB17:%.*]] = sub <4 x i32> [[TMP34]], [[TMP35]]
+// CHECK: store volatile <4 x i32> [[SUB17]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[SUB18:%.*]] = sub <2 x i64> [[TMP36]], [[TMP37]]
+// CHECK: store volatile <2 x i64> [[SUB18]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[SUB19:%.*]] = sub <2 x i64> [[TMP38]], [[TMP39]]
+// CHECK: store volatile <2 x i64> [[SUB19]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP40:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[SUB20:%.*]] = sub <2 x i64> [[TMP40]], [[TMP41]]
+// CHECK: store volatile <2 x i64> [[SUB20]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[SUB21:%.*]] = sub <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: store volatile <2 x i64> [[SUB21]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[SUB22:%.*]] = sub <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: store volatile <2 x i64> [[SUB22]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[SUB23:%.*]] = sub <2 x i64> [[TMP46]], [[TMP47]]
+// CHECK: store volatile <2 x i64> [[SUB23]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[SUB24:%.*]] = fsub <2 x double> [[TMP48]], [[TMP49]]
+// CHECK: store volatile <2 x double> [[SUB24]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_sub(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
sc = sc - sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
sc = sc - bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
sc = bc - sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
uc = uc - uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
uc = uc - bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
uc = bc - uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
ss = ss - ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
ss = ss - bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
ss = bs - ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
us = us - us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
us = us - bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
us = bs - us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
si = si - si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
si = si - bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
si = bi - si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
ui = ui - ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
ui = ui - bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
ui = bi - ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
sl = sl - sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
sl = sl - bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
sl = bl - sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
ul = ul - ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
ul = ul - bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
ul = bl - ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fsub <2 x double> [[VAL1]], [[VAL2]]
fd = fd - fd2;
}
-void test_sub_assign (void)
-{
-// CHECK-LABEL: test_sub_assign
+// CHECK-LABEL: define void @test_sub_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SUB:%.*]] = sub <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[SUB]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SUB1:%.*]] = sub <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[SUB1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SUB2:%.*]] = sub <16 x i8> [[TMP5]], [[TMP4]]
+// CHECK: store volatile <16 x i8> [[SUB2]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SUB3:%.*]] = sub <16 x i8> [[TMP7]], [[TMP6]]
+// CHECK: store volatile <16 x i8> [[SUB3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SUB4:%.*]] = sub <8 x i16> [[TMP9]], [[TMP8]]
+// CHECK: store volatile <8 x i16> [[SUB4]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SUB5:%.*]] = sub <8 x i16> [[TMP11]], [[TMP10]]
+// CHECK: store volatile <8 x i16> [[SUB5]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SUB6:%.*]] = sub <8 x i16> [[TMP13]], [[TMP12]]
+// CHECK: store volatile <8 x i16> [[SUB6]], <8 x i16>* @us, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SUB7:%.*]] = sub <8 x i16> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <8 x i16> [[SUB7]], <8 x i16>* @us, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SUB8:%.*]] = sub <4 x i32> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <4 x i32> [[SUB8]], <4 x i32>* @si, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SUB9:%.*]] = sub <4 x i32> [[TMP19]], [[TMP18]]
+// CHECK: store volatile <4 x i32> [[SUB9]], <4 x i32>* @si, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SUB10:%.*]] = sub <4 x i32> [[TMP21]], [[TMP20]]
+// CHECK: store volatile <4 x i32> [[SUB10]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SUB11:%.*]] = sub <4 x i32> [[TMP23]], [[TMP22]]
+// CHECK: store volatile <4 x i32> [[SUB11]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SUB12:%.*]] = sub <2 x i64> [[TMP25]], [[TMP24]]
+// CHECK: store volatile <2 x i64> [[SUB12]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SUB13:%.*]] = sub <2 x i64> [[TMP27]], [[TMP26]]
+// CHECK: store volatile <2 x i64> [[SUB13]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SUB14:%.*]] = sub <2 x i64> [[TMP29]], [[TMP28]]
+// CHECK: store volatile <2 x i64> [[SUB14]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SUB15:%.*]] = sub <2 x i64> [[TMP31]], [[TMP30]]
+// CHECK: store volatile <2 x i64> [[SUB15]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[SUB16:%.*]] = fsub <2 x double> [[TMP33]], [[TMP32]]
+// CHECK: store volatile <2 x double> [[SUB16]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_sub_assign(void) {
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
sc -= sc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
sc -= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
uc -= uc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = sub <16 x i8> [[VAL1]], [[VAL2]]
uc -= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
ss -= ss2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
ss -= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
us -= us2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = sub <8 x i16> [[VAL1]], [[VAL2]]
us -= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
si -= si2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
si -= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
ui -= ui2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = sub <4 x i32> [[VAL1]], [[VAL2]]
ui -= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
sl -= sl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
sl -= bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
ul -= ul2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = sub <2 x i64> [[VAL1]], [[VAL2]]
ul -= bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: %{{.*}} = fsub <2 x double> [[VAL1]], [[VAL2]]
fd -= fd2;
}
-void test_mul (void)
-{
-// CHECK-LABEL: test_mul
+// CHECK-LABEL: define void @test_mul() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[MUL:%.*]] = mul <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[MUL]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[MUL1:%.*]] = mul <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[MUL1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[MUL2:%.*]] = mul <8 x i16> [[TMP4]], [[TMP5]]
+// CHECK: store volatile <8 x i16> [[MUL2]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[MUL3:%.*]] = mul <8 x i16> [[TMP6]], [[TMP7]]
+// CHECK: store volatile <8 x i16> [[MUL3]], <8 x i16>* @us, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[MUL4:%.*]] = mul <4 x i32> [[TMP8]], [[TMP9]]
+// CHECK: store volatile <4 x i32> [[MUL4]], <4 x i32>* @si, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[MUL5:%.*]] = mul <4 x i32> [[TMP10]], [[TMP11]]
+// CHECK: store volatile <4 x i32> [[MUL5]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[MUL6:%.*]] = mul <2 x i64> [[TMP12]], [[TMP13]]
+// CHECK: store volatile <2 x i64> [[MUL6]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[MUL7:%.*]] = mul <2 x i64> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <2 x i64> [[MUL7]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[MUL8:%.*]] = fmul <2 x double> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <2 x double> [[MUL8]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_mul(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = mul <16 x i8> [[VAL2]], [[VAL1]]
sc = sc * sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = mul <16 x i8> [[VAL2]], [[VAL1]]
uc = uc * uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = mul <8 x i16> [[VAL2]], [[VAL1]]
ss = ss * ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = mul <8 x i16> [[VAL2]], [[VAL1]]
us = us * us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = mul <4 x i32> [[VAL2]], [[VAL1]]
si = si * si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = mul <4 x i32> [[VAL2]], [[VAL1]]
ui = ui * ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = mul <2 x i64> [[VAL2]], [[VAL1]]
sl = sl * sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = mul <2 x i64> [[VAL2]], [[VAL1]]
ul = ul * ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fmul <2 x double> [[VAL1]], [[VAL2]]
fd = fd * fd2;
}
-void test_mul_assign (void)
-{
-// CHECK-LABEL: test_mul_assign
+// CHECK-LABEL: define void @test_mul_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[MUL:%.*]] = mul <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[MUL]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[MUL1:%.*]] = mul <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[MUL1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[MUL2:%.*]] = mul <8 x i16> [[TMP5]], [[TMP4]]
+// CHECK: store volatile <8 x i16> [[MUL2]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[MUL3:%.*]] = mul <8 x i16> [[TMP7]], [[TMP6]]
+// CHECK: store volatile <8 x i16> [[MUL3]], <8 x i16>* @us, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[MUL4:%.*]] = mul <4 x i32> [[TMP9]], [[TMP8]]
+// CHECK: store volatile <4 x i32> [[MUL4]], <4 x i32>* @si, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[MUL5:%.*]] = mul <4 x i32> [[TMP11]], [[TMP10]]
+// CHECK: store volatile <4 x i32> [[MUL5]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[MUL6:%.*]] = mul <2 x i64> [[TMP13]], [[TMP12]]
+// CHECK: store volatile <2 x i64> [[MUL6]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[MUL7:%.*]] = mul <2 x i64> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <2 x i64> [[MUL7]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[MUL8:%.*]] = fmul <2 x double> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <2 x double> [[MUL8]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_mul_assign(void) {
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = mul <16 x i8> [[VAL1]], [[VAL2]]
sc *= sc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = mul <16 x i8> [[VAL1]], [[VAL2]]
uc *= uc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = mul <8 x i16> [[VAL1]], [[VAL2]]
ss *= ss2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = mul <8 x i16> [[VAL1]], [[VAL2]]
us *= us2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = mul <4 x i32> [[VAL1]], [[VAL2]]
si *= si2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = mul <4 x i32> [[VAL1]], [[VAL2]]
ui *= ui2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = mul <2 x i64> [[VAL1]], [[VAL2]]
sl *= sl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = mul <2 x i64> [[VAL1]], [[VAL2]]
ul *= ul2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: %{{.*}} = fmul <2 x double> [[VAL2]], [[VAL1]]
fd *= fd2;
}
-void test_div (void)
-{
-// CHECK-LABEL: test_div
+// CHECK-LABEL: define void @test_div() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[DIV:%.*]] = sdiv <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[DIV]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[DIV1:%.*]] = udiv <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[DIV1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[DIV2:%.*]] = sdiv <8 x i16> [[TMP4]], [[TMP5]]
+// CHECK: store volatile <8 x i16> [[DIV2]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[DIV3:%.*]] = udiv <8 x i16> [[TMP6]], [[TMP7]]
+// CHECK: store volatile <8 x i16> [[DIV3]], <8 x i16>* @us, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[DIV4:%.*]] = sdiv <4 x i32> [[TMP8]], [[TMP9]]
+// CHECK: store volatile <4 x i32> [[DIV4]], <4 x i32>* @si, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[DIV5:%.*]] = udiv <4 x i32> [[TMP10]], [[TMP11]]
+// CHECK: store volatile <4 x i32> [[DIV5]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[DIV6:%.*]] = sdiv <2 x i64> [[TMP12]], [[TMP13]]
+// CHECK: store volatile <2 x i64> [[DIV6]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[DIV7:%.*]] = udiv <2 x i64> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <2 x i64> [[DIV7]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[DIV8:%.*]] = fdiv <2 x double> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <2 x double> [[DIV8]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_div(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = sdiv <16 x i8> [[VAL1]], [[VAL2]]
sc = sc / sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = udiv <16 x i8> [[VAL1]], [[VAL2]]
uc = uc / uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = sdiv <8 x i16> [[VAL1]], [[VAL2]]
ss = ss / ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = udiv <8 x i16> [[VAL1]], [[VAL2]]
us = us / us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = sdiv <4 x i32> [[VAL1]], [[VAL2]]
si = si / si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = udiv <4 x i32> [[VAL1]], [[VAL2]]
ui = ui / ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = sdiv <2 x i64> [[VAL1]], [[VAL2]]
sl = sl / sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = udiv <2 x i64> [[VAL1]], [[VAL2]]
ul = ul / ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: %{{.*}} = fdiv <2 x double> [[VAL1]], [[VAL2]]
fd = fd / fd2;
}
-void test_div_assign (void)
-{
-// CHECK-LABEL: test_div_assign
+// CHECK-LABEL: define void @test_div_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[DIV:%.*]] = sdiv <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[DIV]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[DIV1:%.*]] = udiv <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[DIV1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[DIV2:%.*]] = sdiv <8 x i16> [[TMP5]], [[TMP4]]
+// CHECK: store volatile <8 x i16> [[DIV2]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[DIV3:%.*]] = udiv <8 x i16> [[TMP7]], [[TMP6]]
+// CHECK: store volatile <8 x i16> [[DIV3]], <8 x i16>* @us, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[DIV4:%.*]] = sdiv <4 x i32> [[TMP9]], [[TMP8]]
+// CHECK: store volatile <4 x i32> [[DIV4]], <4 x i32>* @si, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[DIV5:%.*]] = udiv <4 x i32> [[TMP11]], [[TMP10]]
+// CHECK: store volatile <4 x i32> [[DIV5]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[DIV6:%.*]] = sdiv <2 x i64> [[TMP13]], [[TMP12]]
+// CHECK: store volatile <2 x i64> [[DIV6]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[DIV7:%.*]] = udiv <2 x i64> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <2 x i64> [[DIV7]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[DIV8:%.*]] = fdiv <2 x double> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <2 x double> [[DIV8]], <2 x double>* @fd, align 8
+// CHECK: ret void
+void test_div_assign(void) {
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = sdiv <16 x i8> [[VAL1]], [[VAL2]]
sc /= sc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = udiv <16 x i8> [[VAL1]], [[VAL2]]
uc /= uc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = sdiv <8 x i16> [[VAL1]], [[VAL2]]
ss /= ss2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = udiv <8 x i16> [[VAL1]], [[VAL2]]
us /= us2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = sdiv <4 x i32> [[VAL1]], [[VAL2]]
si /= si2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = udiv <4 x i32> [[VAL1]], [[VAL2]]
ui /= ui2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = sdiv <2 x i64> [[VAL1]], [[VAL2]]
sl /= sl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = udiv <2 x i64> [[VAL1]], [[VAL2]]
ul /= ul2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: %{{.*}} = fdiv <2 x double> [[VAL1]], [[VAL2]]
fd /= fd2;
}
-void test_rem (void)
-{
-// CHECK-LABEL: test_rem
+// CHECK-LABEL: define void @test_rem() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[REM:%.*]] = srem <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[REM]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[REM1:%.*]] = urem <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[REM1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[REM2:%.*]] = srem <8 x i16> [[TMP4]], [[TMP5]]
+// CHECK: store volatile <8 x i16> [[REM2]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[REM3:%.*]] = urem <8 x i16> [[TMP6]], [[TMP7]]
+// CHECK: store volatile <8 x i16> [[REM3]], <8 x i16>* @us, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[REM4:%.*]] = srem <4 x i32> [[TMP8]], [[TMP9]]
+// CHECK: store volatile <4 x i32> [[REM4]], <4 x i32>* @si, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[REM5:%.*]] = urem <4 x i32> [[TMP10]], [[TMP11]]
+// CHECK: store volatile <4 x i32> [[REM5]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[REM6:%.*]] = srem <2 x i64> [[TMP12]], [[TMP13]]
+// CHECK: store volatile <2 x i64> [[REM6]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[REM7:%.*]] = urem <2 x i64> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <2 x i64> [[REM7]], <2 x i64>* @ul, align 8
+// CHECK: ret void
+void test_rem(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = srem <16 x i8> [[VAL1]], [[VAL2]]
sc = sc % sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = urem <16 x i8> [[VAL1]], [[VAL2]]
uc = uc % uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = srem <8 x i16> [[VAL1]], [[VAL2]]
ss = ss % ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = urem <8 x i16> [[VAL1]], [[VAL2]]
us = us % us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = srem <4 x i32> [[VAL1]], [[VAL2]]
si = si % si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = urem <4 x i32> [[VAL1]], [[VAL2]]
ui = ui % ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = srem <2 x i64> [[VAL1]], [[VAL2]]
sl = sl % sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = urem <2 x i64> [[VAL1]], [[VAL2]]
ul = ul % ul2;
}
-void test_rem_assign (void)
-{
-// CHECK-LABEL: test_rem_assign
+// CHECK-LABEL: define void @test_rem_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[REM:%.*]] = srem <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[REM]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[REM1:%.*]] = urem <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[REM1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[REM2:%.*]] = srem <8 x i16> [[TMP5]], [[TMP4]]
+// CHECK: store volatile <8 x i16> [[REM2]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[REM3:%.*]] = urem <8 x i16> [[TMP7]], [[TMP6]]
+// CHECK: store volatile <8 x i16> [[REM3]], <8 x i16>* @us, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[REM4:%.*]] = srem <4 x i32> [[TMP9]], [[TMP8]]
+// CHECK: store volatile <4 x i32> [[REM4]], <4 x i32>* @si, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[REM5:%.*]] = urem <4 x i32> [[TMP11]], [[TMP10]]
+// CHECK: store volatile <4 x i32> [[REM5]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[REM6:%.*]] = srem <2 x i64> [[TMP13]], [[TMP12]]
+// CHECK: store volatile <2 x i64> [[REM6]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[REM7:%.*]] = urem <2 x i64> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <2 x i64> [[REM7]], <2 x i64>* @ul, align 8
+// CHECK: ret void
+void test_rem_assign(void) {
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = srem <16 x i8> [[VAL1]], [[VAL2]]
sc %= sc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = urem <16 x i8> [[VAL1]], [[VAL2]]
uc %= uc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = srem <8 x i16> [[VAL1]], [[VAL2]]
ss %= ss2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = urem <8 x i16> [[VAL1]], [[VAL2]]
us %= us2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = srem <4 x i32> [[VAL1]], [[VAL2]]
si %= si2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = urem <4 x i32> [[VAL1]], [[VAL2]]
ui %= ui2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = srem <2 x i64> [[VAL1]], [[VAL2]]
sl %= sl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = urem <2 x i64> [[VAL1]], [[VAL2]]
ul %= ul2;
}
-void test_not (void)
-{
-// CHECK-LABEL: test_not
+// CHECK-LABEL: define void @test_not() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[NEG:%.*]] = xor <16 x i8> [[TMP0]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
+// CHECK: store volatile <16 x i8> [[NEG]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[NEG1:%.*]] = xor <16 x i8> [[TMP1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
+// CHECK: store volatile <16 x i8> [[NEG1]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[NEG2:%.*]] = xor <16 x i8> [[TMP2]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
+// CHECK: store volatile <16 x i8> [[NEG2]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[NEG3:%.*]] = xor <8 x i16> [[TMP3]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: store volatile <8 x i16> [[NEG3]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[NEG4:%.*]] = xor <8 x i16> [[TMP4]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: store volatile <8 x i16> [[NEG4]], <8 x i16>* @us, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[NEG5:%.*]] = xor <8 x i16> [[TMP5]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: store volatile <8 x i16> [[NEG5]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[NEG6:%.*]] = xor <4 x i32> [[TMP6]], <i32 -1, i32 -1, i32 -1, i32 -1>
+// CHECK: store volatile <4 x i32> [[NEG6]], <4 x i32>* @si, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[NEG7:%.*]] = xor <4 x i32> [[TMP7]], <i32 -1, i32 -1, i32 -1, i32 -1>
+// CHECK: store volatile <4 x i32> [[NEG7]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[NEG8:%.*]] = xor <4 x i32> [[TMP8]], <i32 -1, i32 -1, i32 -1, i32 -1>
+// CHECK: store volatile <4 x i32> [[NEG8]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[NEG9:%.*]] = xor <2 x i64> [[TMP9]], <i64 -1, i64 -1>
+// CHECK: store volatile <2 x i64> [[NEG9]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[NEG10:%.*]] = xor <2 x i64> [[TMP10]], <i64 -1, i64 -1>
+// CHECK: store volatile <2 x i64> [[NEG10]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[NEG11:%.*]] = xor <2 x i64> [[TMP11]], <i64 -1, i64 -1>
+// CHECK: store volatile <2 x i64> [[NEG11]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_not(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
sc = ~sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
uc = ~uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>
bc = ~bc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
ss = ~ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
us = ~us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
bs = ~bs2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL]], <i32 -1, i32 -1, i32 -1, i32 -1>
si = ~si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL]], <i32 -1, i32 -1, i32 -1, i32 -1>
ui = ~ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL]], <i32 -1, i32 -1, i32 -1, i32 -1>
bi = ~bi2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL]], <i64 -1, i64 -1>
sl = ~sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL]], <i64 -1, i64 -1>
ul = ~ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL]], <i64 -1, i64 -1>
bl = ~bl2;
}
-void test_and (void)
-{
-// CHECK-LABEL: test_and
+// CHECK-LABEL: define void @test_and() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[AND:%.*]] = and <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[AND]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[AND1:%.*]] = and <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[AND1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[AND2:%.*]] = and <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: store volatile <16 x i8> [[AND2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[AND3:%.*]] = and <16 x i8> [[TMP6]], [[TMP7]]
+// CHECK: store volatile <16 x i8> [[AND3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[AND4:%.*]] = and <16 x i8> [[TMP8]], [[TMP9]]
+// CHECK: store volatile <16 x i8> [[AND4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[AND5:%.*]] = and <16 x i8> [[TMP10]], [[TMP11]]
+// CHECK: store volatile <16 x i8> [[AND5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[AND6:%.*]] = and <16 x i8> [[TMP12]], [[TMP13]]
+// CHECK: store volatile <16 x i8> [[AND6]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[AND7:%.*]] = and <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <8 x i16> [[AND7]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[AND8:%.*]] = and <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <8 x i16> [[AND8]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[AND9:%.*]] = and <8 x i16> [[TMP18]], [[TMP19]]
+// CHECK: store volatile <8 x i16> [[AND9]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[AND10:%.*]] = and <8 x i16> [[TMP20]], [[TMP21]]
+// CHECK: store volatile <8 x i16> [[AND10]], <8 x i16>* @us, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[AND11:%.*]] = and <8 x i16> [[TMP22]], [[TMP23]]
+// CHECK: store volatile <8 x i16> [[AND11]], <8 x i16>* @us, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[AND12:%.*]] = and <8 x i16> [[TMP24]], [[TMP25]]
+// CHECK: store volatile <8 x i16> [[AND12]], <8 x i16>* @us, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[AND13:%.*]] = and <8 x i16> [[TMP26]], [[TMP27]]
+// CHECK: store volatile <8 x i16> [[AND13]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[AND14:%.*]] = and <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: store volatile <4 x i32> [[AND14]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[AND15:%.*]] = and <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: store volatile <4 x i32> [[AND15]], <4 x i32>* @si, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[AND16:%.*]] = and <4 x i32> [[TMP32]], [[TMP33]]
+// CHECK: store volatile <4 x i32> [[AND16]], <4 x i32>* @si, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[AND17:%.*]] = and <4 x i32> [[TMP34]], [[TMP35]]
+// CHECK: store volatile <4 x i32> [[AND17]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[AND18:%.*]] = and <4 x i32> [[TMP36]], [[TMP37]]
+// CHECK: store volatile <4 x i32> [[AND18]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[AND19:%.*]] = and <4 x i32> [[TMP38]], [[TMP39]]
+// CHECK: store volatile <4 x i32> [[AND19]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP40:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[AND20:%.*]] = and <4 x i32> [[TMP40]], [[TMP41]]
+// CHECK: store volatile <4 x i32> [[AND20]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[AND21:%.*]] = and <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: store volatile <2 x i64> [[AND21]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[AND22:%.*]] = and <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: store volatile <2 x i64> [[AND22]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[AND23:%.*]] = and <2 x i64> [[TMP46]], [[TMP47]]
+// CHECK: store volatile <2 x i64> [[AND23]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[AND24:%.*]] = and <2 x i64> [[TMP48]], [[TMP49]]
+// CHECK: store volatile <2 x i64> [[AND24]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[AND25:%.*]] = and <2 x i64> [[TMP50]], [[TMP51]]
+// CHECK: store volatile <2 x i64> [[AND25]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP53:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[AND26:%.*]] = and <2 x i64> [[TMP52]], [[TMP53]]
+// CHECK: store volatile <2 x i64> [[AND26]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP54:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[AND27:%.*]] = and <2 x i64> [[TMP54]], [[TMP55]]
+// CHECK: store volatile <2 x i64> [[AND27]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_and(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = and <16 x i8> [[VAL2]], [[VAL1]]
sc = sc & sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = and <16 x i8> [[VAL2]], [[VAL1]]
sc = sc & bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = and <16 x i8> [[VAL2]], [[VAL1]]
sc = bc & sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = and <16 x i8> [[VAL2]], [[VAL1]]
uc = uc & uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = and <16 x i8> [[VAL2]], [[VAL1]]
uc = uc & bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = and <16 x i8> [[VAL2]], [[VAL1]]
uc = bc & uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = and <16 x i8> [[VAL2]], [[VAL1]]
bc = bc & bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = and <8 x i16> [[VAL2]], [[VAL1]]
ss = ss & ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = and <8 x i16> [[VAL2]], [[VAL1]]
ss = ss & bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = and <8 x i16> [[VAL2]], [[VAL1]]
ss = bs & ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = and <8 x i16> [[VAL2]], [[VAL1]]
us = us & us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = and <8 x i16> [[VAL2]], [[VAL1]]
us = us & bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = and <8 x i16> [[VAL2]], [[VAL1]]
us = bs & us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = and <8 x i16> [[VAL2]], [[VAL1]]
bs = bs & bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = and <4 x i32> [[VAL2]], [[VAL1]]
si = si & si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = and <4 x i32> [[VAL2]], [[VAL1]]
si = si & bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = and <4 x i32> [[VAL2]], [[VAL1]]
si = bi & si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = and <4 x i32> [[VAL2]], [[VAL1]]
ui = ui & ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = and <4 x i32> [[VAL2]], [[VAL1]]
ui = ui & bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = and <4 x i32> [[VAL2]], [[VAL1]]
ui = bi & ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = and <4 x i32> [[VAL2]], [[VAL1]]
bi = bi & bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = and <2 x i64> [[VAL2]], [[VAL1]]
sl = sl & sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = and <2 x i64> [[VAL2]], [[VAL1]]
sl = sl & bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = and <2 x i64> [[VAL2]], [[VAL1]]
sl = bl & sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = and <2 x i64> [[VAL2]], [[VAL1]]
ul = ul & ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = and <2 x i64> [[VAL2]], [[VAL1]]
ul = ul & bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = and <2 x i64> [[VAL2]], [[VAL1]]
ul = bl & ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = and <2 x i64> [[VAL2]], [[VAL1]]
bl = bl & bl2;
}
-void test_and_assign (void)
-{
-// CHECK-LABEL: test_and_assign
+// CHECK-LABEL: define void @test_and_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[AND:%.*]] = and <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[AND]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[AND1:%.*]] = and <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[AND1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[AND2:%.*]] = and <16 x i8> [[TMP5]], [[TMP4]]
+// CHECK: store volatile <16 x i8> [[AND2]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[AND3:%.*]] = and <16 x i8> [[TMP7]], [[TMP6]]
+// CHECK: store volatile <16 x i8> [[AND3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[AND4:%.*]] = and <16 x i8> [[TMP9]], [[TMP8]]
+// CHECK: store volatile <16 x i8> [[AND4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[AND5:%.*]] = and <8 x i16> [[TMP11]], [[TMP10]]
+// CHECK: store volatile <8 x i16> [[AND5]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[AND6:%.*]] = and <8 x i16> [[TMP13]], [[TMP12]]
+// CHECK: store volatile <8 x i16> [[AND6]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[AND7:%.*]] = and <8 x i16> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <8 x i16> [[AND7]], <8 x i16>* @us, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[AND8:%.*]] = and <8 x i16> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <8 x i16> [[AND8]], <8 x i16>* @us, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[AND9:%.*]] = and <8 x i16> [[TMP19]], [[TMP18]]
+// CHECK: store volatile <8 x i16> [[AND9]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[AND10:%.*]] = and <4 x i32> [[TMP21]], [[TMP20]]
+// CHECK: store volatile <4 x i32> [[AND10]], <4 x i32>* @si, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[AND11:%.*]] = and <4 x i32> [[TMP23]], [[TMP22]]
+// CHECK: store volatile <4 x i32> [[AND11]], <4 x i32>* @si, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[AND12:%.*]] = and <4 x i32> [[TMP25]], [[TMP24]]
+// CHECK: store volatile <4 x i32> [[AND12]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[AND13:%.*]] = and <4 x i32> [[TMP27]], [[TMP26]]
+// CHECK: store volatile <4 x i32> [[AND13]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[AND14:%.*]] = and <4 x i32> [[TMP29]], [[TMP28]]
+// CHECK: store volatile <4 x i32> [[AND14]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[AND15:%.*]] = and <2 x i64> [[TMP31]], [[TMP30]]
+// CHECK: store volatile <2 x i64> [[AND15]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[AND16:%.*]] = and <2 x i64> [[TMP33]], [[TMP32]]
+// CHECK: store volatile <2 x i64> [[AND16]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[AND17:%.*]] = and <2 x i64> [[TMP35]], [[TMP34]]
+// CHECK: store volatile <2 x i64> [[AND17]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[AND18:%.*]] = and <2 x i64> [[TMP37]], [[TMP36]]
+// CHECK: store volatile <2 x i64> [[AND18]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[AND19:%.*]] = and <2 x i64> [[TMP39]], [[TMP38]]
+// CHECK: store volatile <2 x i64> [[AND19]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_and_assign(void) {
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = and <16 x i8> [[VAL1]], [[VAL2]]
sc &= sc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = and <16 x i8> [[VAL1]], [[VAL2]]
sc &= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = and <16 x i8> [[VAL1]], [[VAL2]]
uc &= uc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = and <16 x i8> [[VAL1]], [[VAL2]]
uc &= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: %{{.*}} = and <16 x i8> [[VAL1]], [[VAL2]]
bc &= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = and <8 x i16> [[VAL1]], [[VAL2]]
ss &= ss2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = and <8 x i16> [[VAL1]], [[VAL2]]
ss &= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = and <8 x i16> [[VAL1]], [[VAL2]]
us &= us2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = and <8 x i16> [[VAL1]], [[VAL2]]
us &= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: %{{.*}} = and <8 x i16> [[VAL1]], [[VAL2]]
bs &= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = and <4 x i32> [[VAL1]], [[VAL2]]
si &= si2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = and <4 x i32> [[VAL1]], [[VAL2]]
si &= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = and <4 x i32> [[VAL1]], [[VAL2]]
ui &= ui2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = and <4 x i32> [[VAL1]], [[VAL2]]
ui &= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: %{{.*}} = and <4 x i32> [[VAL1]], [[VAL2]]
bi &= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = and <2 x i64> [[VAL1]], [[VAL2]]
sl &= sl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = and <2 x i64> [[VAL1]], [[VAL2]]
sl &= bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = and <2 x i64> [[VAL1]], [[VAL2]]
ul &= ul2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = and <2 x i64> [[VAL1]], [[VAL2]]
ul &= bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: %{{.*}} = and <2 x i64> [[VAL1]], [[VAL2]]
bl &= bl2;
}
-void test_or (void)
-{
-// CHECK-LABEL: test_or
+// CHECK-LABEL: define void @test_or() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[OR:%.*]] = or <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[OR]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[OR1:%.*]] = or <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[OR1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[OR2:%.*]] = or <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: store volatile <16 x i8> [[OR2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[OR3:%.*]] = or <16 x i8> [[TMP6]], [[TMP7]]
+// CHECK: store volatile <16 x i8> [[OR3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[OR4:%.*]] = or <16 x i8> [[TMP8]], [[TMP9]]
+// CHECK: store volatile <16 x i8> [[OR4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[OR5:%.*]] = or <16 x i8> [[TMP10]], [[TMP11]]
+// CHECK: store volatile <16 x i8> [[OR5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[OR6:%.*]] = or <16 x i8> [[TMP12]], [[TMP13]]
+// CHECK: store volatile <16 x i8> [[OR6]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[OR7:%.*]] = or <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <8 x i16> [[OR7]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[OR8:%.*]] = or <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <8 x i16> [[OR8]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[OR9:%.*]] = or <8 x i16> [[TMP18]], [[TMP19]]
+// CHECK: store volatile <8 x i16> [[OR9]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[OR10:%.*]] = or <8 x i16> [[TMP20]], [[TMP21]]
+// CHECK: store volatile <8 x i16> [[OR10]], <8 x i16>* @us, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[OR11:%.*]] = or <8 x i16> [[TMP22]], [[TMP23]]
+// CHECK: store volatile <8 x i16> [[OR11]], <8 x i16>* @us, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[OR12:%.*]] = or <8 x i16> [[TMP24]], [[TMP25]]
+// CHECK: store volatile <8 x i16> [[OR12]], <8 x i16>* @us, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[OR13:%.*]] = or <8 x i16> [[TMP26]], [[TMP27]]
+// CHECK: store volatile <8 x i16> [[OR13]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[OR14:%.*]] = or <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: store volatile <4 x i32> [[OR14]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[OR15:%.*]] = or <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: store volatile <4 x i32> [[OR15]], <4 x i32>* @si, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[OR16:%.*]] = or <4 x i32> [[TMP32]], [[TMP33]]
+// CHECK: store volatile <4 x i32> [[OR16]], <4 x i32>* @si, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[OR17:%.*]] = or <4 x i32> [[TMP34]], [[TMP35]]
+// CHECK: store volatile <4 x i32> [[OR17]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[OR18:%.*]] = or <4 x i32> [[TMP36]], [[TMP37]]
+// CHECK: store volatile <4 x i32> [[OR18]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[OR19:%.*]] = or <4 x i32> [[TMP38]], [[TMP39]]
+// CHECK: store volatile <4 x i32> [[OR19]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP40:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[OR20:%.*]] = or <4 x i32> [[TMP40]], [[TMP41]]
+// CHECK: store volatile <4 x i32> [[OR20]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[OR21:%.*]] = or <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: store volatile <2 x i64> [[OR21]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[OR22:%.*]] = or <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: store volatile <2 x i64> [[OR22]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[OR23:%.*]] = or <2 x i64> [[TMP46]], [[TMP47]]
+// CHECK: store volatile <2 x i64> [[OR23]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[OR24:%.*]] = or <2 x i64> [[TMP48]], [[TMP49]]
+// CHECK: store volatile <2 x i64> [[OR24]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[OR25:%.*]] = or <2 x i64> [[TMP50]], [[TMP51]]
+// CHECK: store volatile <2 x i64> [[OR25]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP53:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[OR26:%.*]] = or <2 x i64> [[TMP52]], [[TMP53]]
+// CHECK: store volatile <2 x i64> [[OR26]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP54:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[OR27:%.*]] = or <2 x i64> [[TMP54]], [[TMP55]]
+// CHECK: store volatile <2 x i64> [[OR27]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_or(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = or <16 x i8> [[VAL2]], [[VAL1]]
sc = sc | sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = or <16 x i8> [[VAL2]], [[VAL1]]
sc = sc | bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = or <16 x i8> [[VAL2]], [[VAL1]]
sc = bc | sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = or <16 x i8> [[VAL2]], [[VAL1]]
uc = uc | uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = or <16 x i8> [[VAL2]], [[VAL1]]
uc = uc | bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = or <16 x i8> [[VAL2]], [[VAL1]]
uc = bc | uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = or <16 x i8> [[VAL2]], [[VAL1]]
bc = bc | bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = or <8 x i16> [[VAL2]], [[VAL1]]
ss = ss | ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = or <8 x i16> [[VAL2]], [[VAL1]]
ss = ss | bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = or <8 x i16> [[VAL2]], [[VAL1]]
ss = bs | ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = or <8 x i16> [[VAL2]], [[VAL1]]
us = us | us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = or <8 x i16> [[VAL2]], [[VAL1]]
us = us | bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = or <8 x i16> [[VAL2]], [[VAL1]]
us = bs | us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = or <8 x i16> [[VAL2]], [[VAL1]]
bs = bs | bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = or <4 x i32> [[VAL2]], [[VAL1]]
si = si | si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = or <4 x i32> [[VAL2]], [[VAL1]]
si = si | bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = or <4 x i32> [[VAL2]], [[VAL1]]
si = bi | si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = or <4 x i32> [[VAL2]], [[VAL1]]
ui = ui | ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = or <4 x i32> [[VAL2]], [[VAL1]]
ui = ui | bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = or <4 x i32> [[VAL2]], [[VAL1]]
ui = bi | ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = or <4 x i32> [[VAL2]], [[VAL1]]
bi = bi | bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = or <2 x i64> [[VAL2]], [[VAL1]]
sl = sl | sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = or <2 x i64> [[VAL2]], [[VAL1]]
sl = sl | bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = or <2 x i64> [[VAL2]], [[VAL1]]
sl = bl | sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = or <2 x i64> [[VAL2]], [[VAL1]]
ul = ul | ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = or <2 x i64> [[VAL2]], [[VAL1]]
ul = ul | bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = or <2 x i64> [[VAL2]], [[VAL1]]
ul = bl | ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = or <2 x i64> [[VAL2]], [[VAL1]]
bl = bl | bl2;
}
-void test_or_assign (void)
-{
-// CHECK-LABEL: test_or_assign
+// CHECK-LABEL: define void @test_or_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[OR:%.*]] = or <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[OR]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[OR1:%.*]] = or <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[OR1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[OR2:%.*]] = or <16 x i8> [[TMP5]], [[TMP4]]
+// CHECK: store volatile <16 x i8> [[OR2]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[OR3:%.*]] = or <16 x i8> [[TMP7]], [[TMP6]]
+// CHECK: store volatile <16 x i8> [[OR3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[OR4:%.*]] = or <16 x i8> [[TMP9]], [[TMP8]]
+// CHECK: store volatile <16 x i8> [[OR4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[OR5:%.*]] = or <8 x i16> [[TMP11]], [[TMP10]]
+// CHECK: store volatile <8 x i16> [[OR5]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[OR6:%.*]] = or <8 x i16> [[TMP13]], [[TMP12]]
+// CHECK: store volatile <8 x i16> [[OR6]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[OR7:%.*]] = or <8 x i16> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <8 x i16> [[OR7]], <8 x i16>* @us, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[OR8:%.*]] = or <8 x i16> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <8 x i16> [[OR8]], <8 x i16>* @us, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[OR9:%.*]] = or <8 x i16> [[TMP19]], [[TMP18]]
+// CHECK: store volatile <8 x i16> [[OR9]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[OR10:%.*]] = or <4 x i32> [[TMP21]], [[TMP20]]
+// CHECK: store volatile <4 x i32> [[OR10]], <4 x i32>* @si, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[OR11:%.*]] = or <4 x i32> [[TMP23]], [[TMP22]]
+// CHECK: store volatile <4 x i32> [[OR11]], <4 x i32>* @si, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[OR12:%.*]] = or <4 x i32> [[TMP25]], [[TMP24]]
+// CHECK: store volatile <4 x i32> [[OR12]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[OR13:%.*]] = or <4 x i32> [[TMP27]], [[TMP26]]
+// CHECK: store volatile <4 x i32> [[OR13]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[OR14:%.*]] = or <4 x i32> [[TMP29]], [[TMP28]]
+// CHECK: store volatile <4 x i32> [[OR14]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[OR15:%.*]] = or <2 x i64> [[TMP31]], [[TMP30]]
+// CHECK: store volatile <2 x i64> [[OR15]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[OR16:%.*]] = or <2 x i64> [[TMP33]], [[TMP32]]
+// CHECK: store volatile <2 x i64> [[OR16]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[OR17:%.*]] = or <2 x i64> [[TMP35]], [[TMP34]]
+// CHECK: store volatile <2 x i64> [[OR17]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[OR18:%.*]] = or <2 x i64> [[TMP37]], [[TMP36]]
+// CHECK: store volatile <2 x i64> [[OR18]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[OR19:%.*]] = or <2 x i64> [[TMP39]], [[TMP38]]
+// CHECK: store volatile <2 x i64> [[OR19]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_or_assign(void) {
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = or <16 x i8> [[VAL1]], [[VAL2]]
sc |= sc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = or <16 x i8> [[VAL1]], [[VAL2]]
sc |= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = or <16 x i8> [[VAL1]], [[VAL2]]
uc |= uc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = or <16 x i8> [[VAL1]], [[VAL2]]
uc |= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: %{{.*}} = or <16 x i8> [[VAL1]], [[VAL2]]
bc |= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = or <8 x i16> [[VAL1]], [[VAL2]]
ss |= ss2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = or <8 x i16> [[VAL1]], [[VAL2]]
ss |= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = or <8 x i16> [[VAL1]], [[VAL2]]
us |= us2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = or <8 x i16> [[VAL1]], [[VAL2]]
us |= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: %{{.*}} = or <8 x i16> [[VAL1]], [[VAL2]]
bs |= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = or <4 x i32> [[VAL1]], [[VAL2]]
si |= si2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = or <4 x i32> [[VAL1]], [[VAL2]]
si |= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = or <4 x i32> [[VAL1]], [[VAL2]]
ui |= ui2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = or <4 x i32> [[VAL1]], [[VAL2]]
ui |= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: %{{.*}} = or <4 x i32> [[VAL1]], [[VAL2]]
bi |= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = or <2 x i64> [[VAL1]], [[VAL2]]
sl |= sl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = or <2 x i64> [[VAL1]], [[VAL2]]
sl |= bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = or <2 x i64> [[VAL1]], [[VAL2]]
ul |= ul2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = or <2 x i64> [[VAL1]], [[VAL2]]
ul |= bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: %{{.*}} = or <2 x i64> [[VAL1]], [[VAL2]]
bl |= bl2;
}
-void test_xor (void)
-{
-// CHECK-LABEL: test_xor
+// CHECK-LABEL: define void @test_xor() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[XOR:%.*]] = xor <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[XOR]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[XOR1:%.*]] = xor <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[XOR1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[XOR2:%.*]] = xor <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: store volatile <16 x i8> [[XOR2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[XOR3:%.*]] = xor <16 x i8> [[TMP6]], [[TMP7]]
+// CHECK: store volatile <16 x i8> [[XOR3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[XOR4:%.*]] = xor <16 x i8> [[TMP8]], [[TMP9]]
+// CHECK: store volatile <16 x i8> [[XOR4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[XOR5:%.*]] = xor <16 x i8> [[TMP10]], [[TMP11]]
+// CHECK: store volatile <16 x i8> [[XOR5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[XOR6:%.*]] = xor <16 x i8> [[TMP12]], [[TMP13]]
+// CHECK: store volatile <16 x i8> [[XOR6]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[XOR7:%.*]] = xor <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <8 x i16> [[XOR7]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[XOR8:%.*]] = xor <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <8 x i16> [[XOR8]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[XOR9:%.*]] = xor <8 x i16> [[TMP18]], [[TMP19]]
+// CHECK: store volatile <8 x i16> [[XOR9]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[XOR10:%.*]] = xor <8 x i16> [[TMP20]], [[TMP21]]
+// CHECK: store volatile <8 x i16> [[XOR10]], <8 x i16>* @us, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[XOR11:%.*]] = xor <8 x i16> [[TMP22]], [[TMP23]]
+// CHECK: store volatile <8 x i16> [[XOR11]], <8 x i16>* @us, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[XOR12:%.*]] = xor <8 x i16> [[TMP24]], [[TMP25]]
+// CHECK: store volatile <8 x i16> [[XOR12]], <8 x i16>* @us, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[XOR13:%.*]] = xor <8 x i16> [[TMP26]], [[TMP27]]
+// CHECK: store volatile <8 x i16> [[XOR13]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[XOR14:%.*]] = xor <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: store volatile <4 x i32> [[XOR14]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[XOR15:%.*]] = xor <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: store volatile <4 x i32> [[XOR15]], <4 x i32>* @si, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[XOR16:%.*]] = xor <4 x i32> [[TMP32]], [[TMP33]]
+// CHECK: store volatile <4 x i32> [[XOR16]], <4 x i32>* @si, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[XOR17:%.*]] = xor <4 x i32> [[TMP34]], [[TMP35]]
+// CHECK: store volatile <4 x i32> [[XOR17]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[XOR18:%.*]] = xor <4 x i32> [[TMP36]], [[TMP37]]
+// CHECK: store volatile <4 x i32> [[XOR18]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[XOR19:%.*]] = xor <4 x i32> [[TMP38]], [[TMP39]]
+// CHECK: store volatile <4 x i32> [[XOR19]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP40:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[XOR20:%.*]] = xor <4 x i32> [[TMP40]], [[TMP41]]
+// CHECK: store volatile <4 x i32> [[XOR20]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[XOR21:%.*]] = xor <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: store volatile <2 x i64> [[XOR21]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[XOR22:%.*]] = xor <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: store volatile <2 x i64> [[XOR22]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[XOR23:%.*]] = xor <2 x i64> [[TMP46]], [[TMP47]]
+// CHECK: store volatile <2 x i64> [[XOR23]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[XOR24:%.*]] = xor <2 x i64> [[TMP48]], [[TMP49]]
+// CHECK: store volatile <2 x i64> [[XOR24]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[XOR25:%.*]] = xor <2 x i64> [[TMP50]], [[TMP51]]
+// CHECK: store volatile <2 x i64> [[XOR25]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP53:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[XOR26:%.*]] = xor <2 x i64> [[TMP52]], [[TMP53]]
+// CHECK: store volatile <2 x i64> [[XOR26]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP54:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[XOR27:%.*]] = xor <2 x i64> [[TMP54]], [[TMP55]]
+// CHECK: store volatile <2 x i64> [[XOR27]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_xor(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL1]], [[VAL2]]
sc = sc ^ sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL1]], [[VAL2]]
sc = sc ^ bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL1]], [[VAL2]]
sc = bc ^ sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL1]], [[VAL2]]
uc = uc ^ uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL1]], [[VAL2]]
uc = uc ^ bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL1]], [[VAL2]]
uc = bc ^ uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL1]], [[VAL2]]
bc = bc ^ bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL1]], [[VAL2]]
ss = ss ^ ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL1]], [[VAL2]]
ss = ss ^ bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL1]], [[VAL2]]
ss = bs ^ ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL1]], [[VAL2]]
us = us ^ us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL1]], [[VAL2]]
us = us ^ bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL1]], [[VAL2]]
us = bs ^ us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL1]], [[VAL2]]
bs = bs ^ bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL1]], [[VAL2]]
si = si ^ si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL1]], [[VAL2]]
si = si ^ bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL1]], [[VAL2]]
si = bi ^ si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL1]], [[VAL2]]
ui = ui ^ ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL1]], [[VAL2]]
ui = ui ^ bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL1]], [[VAL2]]
ui = bi ^ ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL1]], [[VAL2]]
bi = bi ^ bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL1]], [[VAL2]]
sl = sl ^ sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL1]], [[VAL2]]
sl = sl ^ bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL1]], [[VAL2]]
sl = bl ^ sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL1]], [[VAL2]]
ul = ul ^ ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL1]], [[VAL2]]
ul = ul ^ bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL1]], [[VAL2]]
ul = bl ^ ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL1]], [[VAL2]]
bl = bl ^ bl2;
}
-void test_xor_assign (void)
-{
-// CHECK-LABEL: test_xor_assign
+// CHECK-LABEL: define void @test_xor_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[XOR:%.*]] = xor <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[XOR]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[XOR1:%.*]] = xor <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[XOR1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[XOR2:%.*]] = xor <16 x i8> [[TMP5]], [[TMP4]]
+// CHECK: store volatile <16 x i8> [[XOR2]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[XOR3:%.*]] = xor <16 x i8> [[TMP7]], [[TMP6]]
+// CHECK: store volatile <16 x i8> [[XOR3]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[XOR4:%.*]] = xor <16 x i8> [[TMP9]], [[TMP8]]
+// CHECK: store volatile <16 x i8> [[XOR4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[XOR5:%.*]] = xor <8 x i16> [[TMP11]], [[TMP10]]
+// CHECK: store volatile <8 x i16> [[XOR5]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[XOR6:%.*]] = xor <8 x i16> [[TMP13]], [[TMP12]]
+// CHECK: store volatile <8 x i16> [[XOR6]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[XOR7:%.*]] = xor <8 x i16> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <8 x i16> [[XOR7]], <8 x i16>* @us, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[XOR8:%.*]] = xor <8 x i16> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <8 x i16> [[XOR8]], <8 x i16>* @us, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[XOR9:%.*]] = xor <8 x i16> [[TMP19]], [[TMP18]]
+// CHECK: store volatile <8 x i16> [[XOR9]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[XOR10:%.*]] = xor <4 x i32> [[TMP21]], [[TMP20]]
+// CHECK: store volatile <4 x i32> [[XOR10]], <4 x i32>* @si, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[XOR11:%.*]] = xor <4 x i32> [[TMP23]], [[TMP22]]
+// CHECK: store volatile <4 x i32> [[XOR11]], <4 x i32>* @si, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[XOR12:%.*]] = xor <4 x i32> [[TMP25]], [[TMP24]]
+// CHECK: store volatile <4 x i32> [[XOR12]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[XOR13:%.*]] = xor <4 x i32> [[TMP27]], [[TMP26]]
+// CHECK: store volatile <4 x i32> [[XOR13]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[XOR14:%.*]] = xor <4 x i32> [[TMP29]], [[TMP28]]
+// CHECK: store volatile <4 x i32> [[XOR14]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[XOR15:%.*]] = xor <2 x i64> [[TMP31]], [[TMP30]]
+// CHECK: store volatile <2 x i64> [[XOR15]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[XOR16:%.*]] = xor <2 x i64> [[TMP33]], [[TMP32]]
+// CHECK: store volatile <2 x i64> [[XOR16]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[XOR17:%.*]] = xor <2 x i64> [[TMP35]], [[TMP34]]
+// CHECK: store volatile <2 x i64> [[XOR17]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[XOR18:%.*]] = xor <2 x i64> [[TMP37]], [[TMP36]]
+// CHECK: store volatile <2 x i64> [[XOR18]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[XOR19:%.*]] = xor <2 x i64> [[TMP39]], [[TMP38]]
+// CHECK: store volatile <2 x i64> [[XOR19]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_xor_assign(void) {
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL2]], [[VAL1]]
sc ^= sc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL2]], [[VAL1]]
sc ^= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL2]], [[VAL1]]
uc ^= uc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL2]], [[VAL1]]
uc ^= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: %{{.*}} = xor <16 x i8> [[VAL2]], [[VAL1]]
bc ^= bc2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL2]], [[VAL1]]
ss ^= ss2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL2]], [[VAL1]]
ss ^= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL2]], [[VAL1]]
us ^= us2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL2]], [[VAL1]]
us ^= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: %{{.*}} = xor <8 x i16> [[VAL2]], [[VAL1]]
bs ^= bs2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL2]], [[VAL1]]
si ^= si2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL2]], [[VAL1]]
si ^= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL2]], [[VAL1]]
ui ^= ui2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL2]], [[VAL1]]
ui ^= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: %{{.*}} = xor <4 x i32> [[VAL2]], [[VAL1]]
bi ^= bi2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL2]], [[VAL1]]
sl ^= sl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL2]], [[VAL1]]
sl ^= bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL2]], [[VAL1]]
ul ^= ul2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL2]], [[VAL1]]
ul ^= bl2;
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: %{{.*}} = xor <2 x i64> [[VAL2]], [[VAL1]]
bl ^= bl2;
}
-void test_sl (void)
-{
-// CHECK-LABEL: test_sl
+// CHECK-LABEL: define void @test_sl() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[SHL:%.*]] = shl <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[SHL]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[SHL1:%.*]] = shl <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[SHL1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT:%.*]] = insertelement <16 x i32> undef, i32 [[TMP5]], i32 0
+// CHECK: [[SPLAT_SPLAT:%.*]] = shufflevector <16 x i32> [[SPLAT_SPLAT:%.*]]insert, <16 x i32> undef, <16 x i32> zeroinitializer
+// CHECK: [[SH_PROM:%.*]] = trunc <16 x i32> [[SPLAT_SPLAT]] to <16 x i8>
+// CHECK: [[SHL2:%.*]] = shl <16 x i8> [[TMP4]], [[SH_PROM]]
+// CHECK: store volatile <16 x i8> [[SHL2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SHL3:%.*]] = shl <16 x i8> [[TMP6]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+// CHECK: store volatile <16 x i8> [[SHL3]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[SHL4:%.*]] = shl <16 x i8> [[TMP7]], [[TMP8]]
+// CHECK: store volatile <16 x i8> [[SHL4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[SHL5:%.*]] = shl <16 x i8> [[TMP9]], [[TMP10]]
+// CHECK: store volatile <16 x i8> [[SHL5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <16 x i32> undef, i32 [[TMP12]], i32 0
+// CHECK: [[SPLAT_SPLAT7:%.*]] = shufflevector <16 x i32> [[SPLAT_SPLATINSERT6]], <16 x i32> undef, <16 x i32> zeroinitializer
+// CHECK: [[SH_PROM8:%.*]] = trunc <16 x i32> [[SPLAT_SPLAT7]] to <16 x i8>
+// CHECK: [[SHL9:%.*]] = shl <16 x i8> [[TMP11]], [[SH_PROM8]]
+// CHECK: store volatile <16 x i8> [[SHL9]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SHL10:%.*]] = shl <16 x i8> [[TMP13]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+// CHECK: store volatile <16 x i8> [[SHL10]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[SHL11:%.*]] = shl <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <8 x i16> [[SHL11]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[SHL12:%.*]] = shl <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <8 x i16> [[SHL12]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP19:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <8 x i32> undef, i32 [[TMP19]], i32 0
+// CHECK: [[SPLAT_SPLAT14:%.*]] = shufflevector <8 x i32> [[SPLAT_SPLATINSERT13]], <8 x i32> undef, <8 x i32> zeroinitializer
+// CHECK: [[SH_PROM15:%.*]] = trunc <8 x i32> [[SPLAT_SPLAT14]] to <8 x i16>
+// CHECK: [[SHL16:%.*]] = shl <8 x i16> [[TMP18]], [[SH_PROM15]]
+// CHECK: store volatile <8 x i16> [[SHL16]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SHL17:%.*]] = shl <8 x i16> [[TMP20]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
+// CHECK: store volatile <8 x i16> [[SHL17]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[SHL18:%.*]] = shl <8 x i16> [[TMP21]], [[TMP22]]
+// CHECK: store volatile <8 x i16> [[SHL18]], <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[SHL19:%.*]] = shl <8 x i16> [[TMP23]], [[TMP24]]
+// CHECK: store volatile <8 x i16> [[SHL19]], <8 x i16>* @us, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP26:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT20:%.*]] = insertelement <8 x i32> undef, i32 [[TMP26]], i32 0
+// CHECK: [[SPLAT_SPLAT21:%.*]] = shufflevector <8 x i32> [[SPLAT_SPLATINSERT20]], <8 x i32> undef, <8 x i32> zeroinitializer
+// CHECK: [[SH_PROM22:%.*]] = trunc <8 x i32> [[SPLAT_SPLAT21]] to <8 x i16>
+// CHECK: [[SHL23:%.*]] = shl <8 x i16> [[TMP25]], [[SH_PROM22]]
+// CHECK: store volatile <8 x i16> [[SHL23]], <8 x i16>* @us, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SHL24:%.*]] = shl <8 x i16> [[TMP27]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
+// CHECK: store volatile <8 x i16> [[SHL24]], <8 x i16>* @us, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[SHL25:%.*]] = shl <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: store volatile <4 x i32> [[SHL25]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[SHL26:%.*]] = shl <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: store volatile <4 x i32> [[SHL26]], <4 x i32>* @si, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP33:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT27:%.*]] = insertelement <4 x i32> undef, i32 [[TMP33]], i32 0
+// CHECK: [[SPLAT_SPLAT28:%.*]] = shufflevector <4 x i32> [[SPLAT_SPLATINSERT27]], <4 x i32> undef, <4 x i32> zeroinitializer
+// CHECK: [[SHL29:%.*]] = shl <4 x i32> [[TMP32]], [[SPLAT_SPLAT28]]
+// CHECK: store volatile <4 x i32> [[SHL29]], <4 x i32>* @si, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHL30:%.*]] = shl <4 x i32> [[TMP34]], <i32 5, i32 5, i32 5, i32 5>
+// CHECK: store volatile <4 x i32> [[SHL30]], <4 x i32>* @si, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[SHL31:%.*]] = shl <4 x i32> [[TMP35]], [[TMP36]]
+// CHECK: store volatile <4 x i32> [[SHL31]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[SHL32:%.*]] = shl <4 x i32> [[TMP37]], [[TMP38]]
+// CHECK: store volatile <4 x i32> [[SHL32]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP40:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT33:%.*]] = insertelement <4 x i32> undef, i32 [[TMP40]], i32 0
+// CHECK: [[SPLAT_SPLAT34:%.*]] = shufflevector <4 x i32> [[SPLAT_SPLATINSERT33]], <4 x i32> undef, <4 x i32> zeroinitializer
+// CHECK: [[SHL35:%.*]] = shl <4 x i32> [[TMP39]], [[SPLAT_SPLAT34]]
+// CHECK: store volatile <4 x i32> [[SHL35]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHL36:%.*]] = shl <4 x i32> [[TMP41]], <i32 5, i32 5, i32 5, i32 5>
+// CHECK: store volatile <4 x i32> [[SHL36]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[SHL37:%.*]] = shl <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: store volatile <2 x i64> [[SHL37]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[SHL38:%.*]] = shl <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: store volatile <2 x i64> [[SHL38]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT39:%.*]] = insertelement <2 x i32> undef, i32 [[TMP47]], i32 0
+// CHECK: [[SPLAT_SPLAT40:%.*]] = shufflevector <2 x i32> [[SPLAT_SPLATINSERT39]], <2 x i32> undef, <2 x i32> zeroinitializer
+// CHECK: [[SH_PROM41:%.*]] = zext <2 x i32> [[SPLAT_SPLAT40]] to <2 x i64>
+// CHECK: [[SHL42:%.*]] = shl <2 x i64> [[TMP46]], [[SH_PROM41]]
+// CHECK: store volatile <2 x i64> [[SHL42]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SHL43:%.*]] = shl <2 x i64> [[TMP48]], <i64 5, i64 5>
+// CHECK: store volatile <2 x i64> [[SHL43]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[SHL44:%.*]] = shl <2 x i64> [[TMP49]], [[TMP50]]
+// CHECK: store volatile <2 x i64> [[SHL44]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[SHL45:%.*]] = shl <2 x i64> [[TMP51]], [[TMP52]]
+// CHECK: store volatile <2 x i64> [[SHL45]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP53:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP54:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT46:%.*]] = insertelement <2 x i32> undef, i32 [[TMP54]], i32 0
+// CHECK: [[SPLAT_SPLAT47:%.*]] = shufflevector <2 x i32> [[SPLAT_SPLATINSERT46]], <2 x i32> undef, <2 x i32> zeroinitializer
+// CHECK: [[SH_PROM48:%.*]] = zext <2 x i32> [[SPLAT_SPLAT47]] to <2 x i64>
+// CHECK: [[SHL49:%.*]] = shl <2 x i64> [[TMP53]], [[SH_PROM48]]
+// CHECK: store volatile <2 x i64> [[SHL49]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SHL50:%.*]] = shl <2 x i64> [[TMP55]], <i64 5, i64 5>
+// CHECK: store volatile <2 x i64> [[SHL50]], <2 x i64>* @ul, align 8
+// CHECK: ret void
+void test_sl(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
sc = sc << sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
sc = sc << uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <16 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <16 x i32> [[T2]], <16 x i32> undef, <16 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = trunc <16 x i32> [[T3]] to <16 x i8>
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
sc = sc << cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
sc = sc << 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
uc = uc << sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
uc = uc << uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <16 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <16 x i32> [[T2]], <16 x i32> undef, <16 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = trunc <16 x i32> [[T3]] to <16 x i8>
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
uc = uc << cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
uc = uc << 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
ss = ss << ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
ss = ss << us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <8 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <8 x i32> [[T2]], <8 x i32> undef, <8 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = trunc <8 x i32> [[T3]] to <8 x i16>
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
ss = ss << cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
ss = ss << 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
us = us << ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
us = us << us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <8 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <8 x i32> [[T2]], <8 x i32> undef, <8 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = trunc <8 x i32> [[T3]] to <8 x i16>
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
us = us << cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
us = us << 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
si = si << si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
si = si << ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T3:%[^ ]+]] = insertelement <4 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[CNT:%[^ ]+]] = shufflevector <4 x i32> [[T3]], <4 x i32> undef, <4 x i32> zeroinitializer
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
si = si << cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], <i32 5, i32 5, i32 5, i32 5>
si = si << 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
ui = ui << si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
ui = ui << ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T3:%[^ ]+]] = insertelement <4 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[CNT:%[^ ]+]] = shufflevector <4 x i32> [[T3]], <4 x i32> undef, <4 x i32> zeroinitializer
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
ui = ui << cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], <i32 5, i32 5, i32 5, i32 5>
ui = ui << 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
sl = sl << sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
sl = sl << ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <2 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <2 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = zext <2 x i32> [[T3]] to <2 x i64>
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
sl = sl << cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], <i64 5, i64 5>
sl = sl << 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
ul = ul << sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
ul = ul << ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <2 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <2 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = zext <2 x i32> [[T3]] to <2 x i64>
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
ul = ul << cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], <i64 5, i64 5>
ul = ul << 5;
}
-void test_sl_assign (void)
-{
-// CHECK-LABEL: test_sl_assign
+// CHECK-LABEL: define void @test_sl_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SHL:%.*]] = shl <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[SHL]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SHL1:%.*]] = shl <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[SHL1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT:%.*]] = insertelement <16 x i32> undef, i32 [[TMP4]], i32 0
+// CHECK: [[SPLAT_SPLAT:%.*]] = shufflevector <16 x i32> [[SPLAT_SPLAT:%.*]]insert, <16 x i32> undef, <16 x i32> zeroinitializer
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SH_PROM:%.*]] = trunc <16 x i32> [[SPLAT_SPLAT]] to <16 x i8>
+// CHECK: [[SHL2:%.*]] = shl <16 x i8> [[TMP5]], [[SH_PROM]]
+// CHECK: store volatile <16 x i8> [[SHL2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SHL3:%.*]] = shl <16 x i8> [[TMP6]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+// CHECK: store volatile <16 x i8> [[SHL3]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SHL4:%.*]] = shl <16 x i8> [[TMP8]], [[TMP7]]
+// CHECK: store volatile <16 x i8> [[SHL4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SHL5:%.*]] = shl <16 x i8> [[TMP10]], [[TMP9]]
+// CHECK: store volatile <16 x i8> [[SHL5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <16 x i32> undef, i32 [[TMP11]], i32 0
+// CHECK: [[SPLAT_SPLAT7:%.*]] = shufflevector <16 x i32> [[SPLAT_SPLATINSERT6]], <16 x i32> undef, <16 x i32> zeroinitializer
+// CHECK: [[TMP12:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SH_PROM8:%.*]] = trunc <16 x i32> [[SPLAT_SPLAT7]] to <16 x i8>
+// CHECK: [[SHL9:%.*]] = shl <16 x i8> [[TMP12]], [[SH_PROM8]]
+// CHECK: store volatile <16 x i8> [[SHL9]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SHL10:%.*]] = shl <16 x i8> [[TMP13]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+// CHECK: store volatile <16 x i8> [[SHL10]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SHL11:%.*]] = shl <8 x i16> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <8 x i16> [[SHL11]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SHL12:%.*]] = shl <8 x i16> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <8 x i16> [[SHL12]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <8 x i32> undef, i32 [[TMP18]], i32 0
+// CHECK: [[SPLAT_SPLAT14:%.*]] = shufflevector <8 x i32> [[SPLAT_SPLATINSERT13]], <8 x i32> undef, <8 x i32> zeroinitializer
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SH_PROM15:%.*]] = trunc <8 x i32> [[SPLAT_SPLAT14]] to <8 x i16>
+// CHECK: [[SHL16:%.*]] = shl <8 x i16> [[TMP19]], [[SH_PROM15]]
+// CHECK: store volatile <8 x i16> [[SHL16]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SHL17:%.*]] = shl <8 x i16> [[TMP20]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
+// CHECK: store volatile <8 x i16> [[SHL17]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SHL18:%.*]] = shl <8 x i16> [[TMP22]], [[TMP21]]
+// CHECK: store volatile <8 x i16> [[SHL18]], <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SHL19:%.*]] = shl <8 x i16> [[TMP24]], [[TMP23]]
+// CHECK: store volatile <8 x i16> [[SHL19]], <8 x i16>* @us, align 8
+// CHECK: [[TMP25:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT20:%.*]] = insertelement <8 x i32> undef, i32 [[TMP25]], i32 0
+// CHECK: [[SPLAT_SPLAT21:%.*]] = shufflevector <8 x i32> [[SPLAT_SPLATINSERT20]], <8 x i32> undef, <8 x i32> zeroinitializer
+// CHECK: [[TMP26:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SH_PROM22:%.*]] = trunc <8 x i32> [[SPLAT_SPLAT21]] to <8 x i16>
+// CHECK: [[SHL23:%.*]] = shl <8 x i16> [[TMP26]], [[SH_PROM22]]
+// CHECK: store volatile <8 x i16> [[SHL23]], <8 x i16>* @us, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SHL24:%.*]] = shl <8 x i16> [[TMP27]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
+// CHECK: store volatile <8 x i16> [[SHL24]], <8 x i16>* @us, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHL25:%.*]] = shl <4 x i32> [[TMP29]], [[TMP28]]
+// CHECK: store volatile <4 x i32> [[SHL25]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHL26:%.*]] = shl <4 x i32> [[TMP31]], [[TMP30]]
+// CHECK: store volatile <4 x i32> [[SHL26]], <4 x i32>* @si, align 8
+// CHECK: [[TMP32:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT27:%.*]] = insertelement <4 x i32> undef, i32 [[TMP32]], i32 0
+// CHECK: [[SPLAT_SPLAT28:%.*]] = shufflevector <4 x i32> [[SPLAT_SPLATINSERT27]], <4 x i32> undef, <4 x i32> zeroinitializer
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHL29:%.*]] = shl <4 x i32> [[TMP33]], [[SPLAT_SPLAT28]]
+// CHECK: store volatile <4 x i32> [[SHL29]], <4 x i32>* @si, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHL30:%.*]] = shl <4 x i32> [[TMP34]], <i32 5, i32 5, i32 5, i32 5>
+// CHECK: store volatile <4 x i32> [[SHL30]], <4 x i32>* @si, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHL31:%.*]] = shl <4 x i32> [[TMP36]], [[TMP35]]
+// CHECK: store volatile <4 x i32> [[SHL31]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHL32:%.*]] = shl <4 x i32> [[TMP38]], [[TMP37]]
+// CHECK: store volatile <4 x i32> [[SHL32]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP39:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT33:%.*]] = insertelement <4 x i32> undef, i32 [[TMP39]], i32 0
+// CHECK: [[SPLAT_SPLAT34:%.*]] = shufflevector <4 x i32> [[SPLAT_SPLATINSERT33]], <4 x i32> undef, <4 x i32> zeroinitializer
+// CHECK: [[TMP40:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHL35:%.*]] = shl <4 x i32> [[TMP40]], [[SPLAT_SPLAT34]]
+// CHECK: store volatile <4 x i32> [[SHL35]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHL36:%.*]] = shl <4 x i32> [[TMP41]], <i32 5, i32 5, i32 5, i32 5>
+// CHECK: store volatile <4 x i32> [[SHL36]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SHL37:%.*]] = shl <2 x i64> [[TMP43]], [[TMP42]]
+// CHECK: store volatile <2 x i64> [[SHL37]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SHL38:%.*]] = shl <2 x i64> [[TMP45]], [[TMP44]]
+// CHECK: store volatile <2 x i64> [[SHL38]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT39:%.*]] = insertelement <2 x i32> undef, i32 [[TMP46]], i32 0
+// CHECK: [[SPLAT_SPLAT40:%.*]] = shufflevector <2 x i32> [[SPLAT_SPLATINSERT39]], <2 x i32> undef, <2 x i32> zeroinitializer
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SH_PROM41:%.*]] = zext <2 x i32> [[SPLAT_SPLAT40]] to <2 x i64>
+// CHECK: [[SHL42:%.*]] = shl <2 x i64> [[TMP47]], [[SH_PROM41]]
+// CHECK: store volatile <2 x i64> [[SHL42]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SHL43:%.*]] = shl <2 x i64> [[TMP48]], <i64 5, i64 5>
+// CHECK: store volatile <2 x i64> [[SHL43]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SHL44:%.*]] = shl <2 x i64> [[TMP50]], [[TMP49]]
+// CHECK: store volatile <2 x i64> [[SHL44]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SHL45:%.*]] = shl <2 x i64> [[TMP52]], [[TMP51]]
+// CHECK: store volatile <2 x i64> [[SHL45]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP53:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT46:%.*]] = insertelement <2 x i32> undef, i32 [[TMP53]], i32 0
+// CHECK: [[SPLAT_SPLAT47:%.*]] = shufflevector <2 x i32> [[SPLAT_SPLATINSERT46]], <2 x i32> undef, <2 x i32> zeroinitializer
+// CHECK: [[TMP54:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SH_PROM48:%.*]] = zext <2 x i32> [[SPLAT_SPLAT47]] to <2 x i64>
+// CHECK: [[SHL49:%.*]] = shl <2 x i64> [[TMP54]], [[SH_PROM48]]
+// CHECK: store volatile <2 x i64> [[SHL49]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SHL50:%.*]] = shl <2 x i64> [[TMP55]], <i64 5, i64 5>
+// CHECK: store volatile <2 x i64> [[SHL50]], <2 x i64>* @ul, align 8
+// CHECK: ret void
+void test_sl_assign(void) {
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
sc <<= sc2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
sc <<= uc2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <16 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <16 x i32> [[T2]], <16 x i32> undef, <16 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[CNT:%[^ ]+]] = trunc <16 x i32> [[T3]] to <16 x i8>
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
sc <<= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
sc <<= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
uc <<= sc2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
uc <<= uc2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <16 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <16 x i32> [[T2]], <16 x i32> undef, <16 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[CNT:%[^ ]+]] = trunc <16 x i32> [[T3]] to <16 x i8>
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], [[CNT]]
uc <<= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = shl <16 x i8> [[VAL]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
uc <<= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
ss <<= ss2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
ss <<= us2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <8 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <8 x i32> [[T2]], <8 x i32> undef, <8 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[CNT:%[^ ]+]] = trunc <8 x i32> [[T3]] to <8 x i16>
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
ss <<= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
ss <<= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
us <<= ss2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
us <<= us2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <8 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <8 x i32> [[T2]], <8 x i32> undef, <8 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[CNT:%[^ ]+]] = trunc <8 x i32> [[T3]] to <8 x i16>
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], [[CNT]]
us <<= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = shl <8 x i16> [[VAL]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
us <<= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
si <<= si2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
si <<= ui2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T3:%[^ ]+]] = insertelement <4 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[CNT:%[^ ]+]] = shufflevector <4 x i32> [[T3]], <4 x i32> undef, <4 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
si <<= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], <i32 5, i32 5, i32 5, i32 5>
si <<= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
ui <<= si2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
ui <<= ui2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T3:%[^ ]+]] = insertelement <4 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[CNT:%[^ ]+]] = shufflevector <4 x i32> [[T3]], <4 x i32> undef, <4 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], [[CNT]]
ui <<= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = shl <4 x i32> [[VAL]], <i32 5, i32 5, i32 5, i32 5>
ui <<= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
sl <<= sl2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
sl <<= ul2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <2 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <2 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[CNT:%[^ ]+]] = zext <2 x i32> [[T3]] to <2 x i64>
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
sl <<= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], <i64 5, i64 5>
sl <<= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
ul <<= sl2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
ul <<= ul2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <2 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <2 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[CNT:%[^ ]+]] = zext <2 x i32> [[T3]] to <2 x i64>
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], [[CNT]]
ul <<= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = shl <2 x i64> [[VAL]], <i64 5, i64 5>
ul <<= 5;
}
-void test_sr (void)
-{
-// CHECK-LABEL: test_sr
+// CHECK-LABEL: define void @test_sr() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[SHR:%.*]] = ashr <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: store volatile <16 x i8> [[SHR]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[SHR1:%.*]] = ashr <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: store volatile <16 x i8> [[SHR1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT:%.*]] = insertelement <16 x i32> undef, i32 [[TMP5]], i32 0
+// CHECK: [[SPLAT_SPLAT:%.*]] = shufflevector <16 x i32> [[SPLAT_SPLAT:%.*]]insert, <16 x i32> undef, <16 x i32> zeroinitializer
+// CHECK: [[SH_PROM:%.*]] = trunc <16 x i32> [[SPLAT_SPLAT]] to <16 x i8>
+// CHECK: [[SHR2:%.*]] = ashr <16 x i8> [[TMP4]], [[SH_PROM]]
+// CHECK: store volatile <16 x i8> [[SHR2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SHR3:%.*]] = ashr <16 x i8> [[TMP6]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+// CHECK: store volatile <16 x i8> [[SHR3]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[SHR4:%.*]] = lshr <16 x i8> [[TMP7]], [[TMP8]]
+// CHECK: store volatile <16 x i8> [[SHR4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[SHR5:%.*]] = lshr <16 x i8> [[TMP9]], [[TMP10]]
+// CHECK: store volatile <16 x i8> [[SHR5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <16 x i32> undef, i32 [[TMP12]], i32 0
+// CHECK: [[SPLAT_SPLAT7:%.*]] = shufflevector <16 x i32> [[SPLAT_SPLATINSERT6]], <16 x i32> undef, <16 x i32> zeroinitializer
+// CHECK: [[SH_PROM8:%.*]] = trunc <16 x i32> [[SPLAT_SPLAT7]] to <16 x i8>
+// CHECK: [[SHR9:%.*]] = lshr <16 x i8> [[TMP11]], [[SH_PROM8]]
+// CHECK: store volatile <16 x i8> [[SHR9]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SHR10:%.*]] = lshr <16 x i8> [[TMP13]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+// CHECK: store volatile <16 x i8> [[SHR10]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[SHR11:%.*]] = ashr <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: store volatile <8 x i16> [[SHR11]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[SHR12:%.*]] = ashr <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: store volatile <8 x i16> [[SHR12]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP19:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <8 x i32> undef, i32 [[TMP19]], i32 0
+// CHECK: [[SPLAT_SPLAT14:%.*]] = shufflevector <8 x i32> [[SPLAT_SPLATINSERT13]], <8 x i32> undef, <8 x i32> zeroinitializer
+// CHECK: [[SH_PROM15:%.*]] = trunc <8 x i32> [[SPLAT_SPLAT14]] to <8 x i16>
+// CHECK: [[SHR16:%.*]] = ashr <8 x i16> [[TMP18]], [[SH_PROM15]]
+// CHECK: store volatile <8 x i16> [[SHR16]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SHR17:%.*]] = ashr <8 x i16> [[TMP20]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
+// CHECK: store volatile <8 x i16> [[SHR17]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[SHR18:%.*]] = lshr <8 x i16> [[TMP21]], [[TMP22]]
+// CHECK: store volatile <8 x i16> [[SHR18]], <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[SHR19:%.*]] = lshr <8 x i16> [[TMP23]], [[TMP24]]
+// CHECK: store volatile <8 x i16> [[SHR19]], <8 x i16>* @us, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP26:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT20:%.*]] = insertelement <8 x i32> undef, i32 [[TMP26]], i32 0
+// CHECK: [[SPLAT_SPLAT21:%.*]] = shufflevector <8 x i32> [[SPLAT_SPLATINSERT20]], <8 x i32> undef, <8 x i32> zeroinitializer
+// CHECK: [[SH_PROM22:%.*]] = trunc <8 x i32> [[SPLAT_SPLAT21]] to <8 x i16>
+// CHECK: [[SHR23:%.*]] = lshr <8 x i16> [[TMP25]], [[SH_PROM22]]
+// CHECK: store volatile <8 x i16> [[SHR23]], <8 x i16>* @us, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SHR24:%.*]] = lshr <8 x i16> [[TMP27]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
+// CHECK: store volatile <8 x i16> [[SHR24]], <8 x i16>* @us, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[SHR25:%.*]] = ashr <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: store volatile <4 x i32> [[SHR25]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[SHR26:%.*]] = ashr <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: store volatile <4 x i32> [[SHR26]], <4 x i32>* @si, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP33:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT27:%.*]] = insertelement <4 x i32> undef, i32 [[TMP33]], i32 0
+// CHECK: [[SPLAT_SPLAT28:%.*]] = shufflevector <4 x i32> [[SPLAT_SPLATINSERT27]], <4 x i32> undef, <4 x i32> zeroinitializer
+// CHECK: [[SHR29:%.*]] = ashr <4 x i32> [[TMP32]], [[SPLAT_SPLAT28]]
+// CHECK: store volatile <4 x i32> [[SHR29]], <4 x i32>* @si, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHR30:%.*]] = ashr <4 x i32> [[TMP34]], <i32 5, i32 5, i32 5, i32 5>
+// CHECK: store volatile <4 x i32> [[SHR30]], <4 x i32>* @si, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[SHR31:%.*]] = lshr <4 x i32> [[TMP35]], [[TMP36]]
+// CHECK: store volatile <4 x i32> [[SHR31]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[SHR32:%.*]] = lshr <4 x i32> [[TMP37]], [[TMP38]]
+// CHECK: store volatile <4 x i32> [[SHR32]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP40:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT33:%.*]] = insertelement <4 x i32> undef, i32 [[TMP40]], i32 0
+// CHECK: [[SPLAT_SPLAT34:%.*]] = shufflevector <4 x i32> [[SPLAT_SPLATINSERT33]], <4 x i32> undef, <4 x i32> zeroinitializer
+// CHECK: [[SHR35:%.*]] = lshr <4 x i32> [[TMP39]], [[SPLAT_SPLAT34]]
+// CHECK: store volatile <4 x i32> [[SHR35]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHR36:%.*]] = lshr <4 x i32> [[TMP41]], <i32 5, i32 5, i32 5, i32 5>
+// CHECK: store volatile <4 x i32> [[SHR36]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[SHR37:%.*]] = ashr <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: store volatile <2 x i64> [[SHR37]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[SHR38:%.*]] = ashr <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: store volatile <2 x i64> [[SHR38]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT39:%.*]] = insertelement <2 x i32> undef, i32 [[TMP47]], i32 0
+// CHECK: [[SPLAT_SPLAT40:%.*]] = shufflevector <2 x i32> [[SPLAT_SPLATINSERT39]], <2 x i32> undef, <2 x i32> zeroinitializer
+// CHECK: [[SH_PROM41:%.*]] = zext <2 x i32> [[SPLAT_SPLAT40]] to <2 x i64>
+// CHECK: [[SHR42:%.*]] = ashr <2 x i64> [[TMP46]], [[SH_PROM41]]
+// CHECK: store volatile <2 x i64> [[SHR42]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SHR43:%.*]] = ashr <2 x i64> [[TMP48]], <i64 5, i64 5>
+// CHECK: store volatile <2 x i64> [[SHR43]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[SHR44:%.*]] = lshr <2 x i64> [[TMP49]], [[TMP50]]
+// CHECK: store volatile <2 x i64> [[SHR44]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[SHR45:%.*]] = lshr <2 x i64> [[TMP51]], [[TMP52]]
+// CHECK: store volatile <2 x i64> [[SHR45]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP53:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP54:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT46:%.*]] = insertelement <2 x i32> undef, i32 [[TMP54]], i32 0
+// CHECK: [[SPLAT_SPLAT47:%.*]] = shufflevector <2 x i32> [[SPLAT_SPLATINSERT46]], <2 x i32> undef, <2 x i32> zeroinitializer
+// CHECK: [[SH_PROM48:%.*]] = zext <2 x i32> [[SPLAT_SPLAT47]] to <2 x i64>
+// CHECK: [[SHR49:%.*]] = lshr <2 x i64> [[TMP53]], [[SH_PROM48]]
+// CHECK: store volatile <2 x i64> [[SHR49]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SHR50:%.*]] = lshr <2 x i64> [[TMP55]], <i64 5, i64 5>
+// CHECK: store volatile <2 x i64> [[SHR50]], <2 x i64>* @ul, align 8
+// CHECK: ret void
+void test_sr(void) {
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = ashr <16 x i8> [[VAL]], [[CNT]]
sc = sc >> sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = ashr <16 x i8> [[VAL]], [[CNT]]
sc = sc >> uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <16 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <16 x i32> [[T2]], <16 x i32> undef, <16 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = trunc <16 x i32> [[T3]] to <16 x i8>
-// CHECK: %{{.*}} = ashr <16 x i8> [[VAL]], [[CNT]]
sc = sc >> cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = ashr <16 x i8> [[VAL]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
sc = sc >> 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: %{{.*}} = lshr <16 x i8> [[VAL]], [[CNT]]
uc = uc >> sc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: %{{.*}} = lshr <16 x i8> [[VAL]], [[CNT]]
uc = uc >> uc2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <16 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <16 x i32> [[T2]], <16 x i32> undef, <16 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = trunc <16 x i32> [[T3]] to <16 x i8>
-// CHECK: %{{.*}} = lshr <16 x i8> [[VAL]], [[CNT]]
uc = uc >> cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = lshr <16 x i8> [[VAL]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
uc = uc >> 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = ashr <8 x i16> [[VAL]], [[CNT]]
ss = ss >> ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = ashr <8 x i16> [[VAL]], [[CNT]]
ss = ss >> us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <8 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <8 x i32> [[T2]], <8 x i32> undef, <8 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = trunc <8 x i32> [[T3]] to <8 x i16>
-// CHECK: %{{.*}} = ashr <8 x i16> [[VAL]], [[CNT]]
ss = ss >> cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = ashr <8 x i16> [[VAL]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
ss = ss >> 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: %{{.*}} = lshr <8 x i16> [[VAL]], [[CNT]]
us = us >> ss2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: %{{.*}} = lshr <8 x i16> [[VAL]], [[CNT]]
us = us >> us2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <8 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <8 x i32> [[T2]], <8 x i32> undef, <8 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = trunc <8 x i32> [[T3]] to <8 x i16>
-// CHECK: %{{.*}} = lshr <8 x i16> [[VAL]], [[CNT]]
us = us >> cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = lshr <8 x i16> [[VAL]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
us = us >> 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = ashr <4 x i32> [[VAL]], [[CNT]]
si = si >> si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = ashr <4 x i32> [[VAL]], [[CNT]]
si = si >> ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T3:%[^ ]+]] = insertelement <4 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[CNT:%[^ ]+]] = shufflevector <4 x i32> [[T3]], <4 x i32> undef, <4 x i32> zeroinitializer
-// CHECK: %{{.*}} = ashr <4 x i32> [[VAL]], [[CNT]]
si = si >> cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = ashr <4 x i32> [[VAL]], <i32 5, i32 5, i32 5, i32 5>
si = si >> 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: %{{.*}} = lshr <4 x i32> [[VAL]], [[CNT]]
ui = ui >> si2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: %{{.*}} = lshr <4 x i32> [[VAL]], [[CNT]]
ui = ui >> ui2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T3:%[^ ]+]] = insertelement <4 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[CNT:%[^ ]+]] = shufflevector <4 x i32> [[T3]], <4 x i32> undef, <4 x i32> zeroinitializer
-// CHECK: %{{.*}} = lshr <4 x i32> [[VAL]], [[CNT]]
ui = ui >> cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = lshr <4 x i32> [[VAL]], <i32 5, i32 5, i32 5, i32 5>
ui = ui >> 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = ashr <2 x i64> [[VAL]], [[CNT]]
sl = sl >> sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = ashr <2 x i64> [[VAL]], [[CNT]]
sl = sl >> ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <2 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <2 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = zext <2 x i32> [[T3]] to <2 x i64>
-// CHECK: %{{.*}} = ashr <2 x i64> [[VAL]], [[CNT]]
sl = sl >> cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = ashr <2 x i64> [[VAL]], <i64 5, i64 5>
sl = sl >> 5;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: %{{.*}} = lshr <2 x i64> [[VAL]], [[CNT]]
ul = ul >> sl2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: %{{.*}} = lshr <2 x i64> [[VAL]], [[CNT]]
ul = ul >> ul2;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <2 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <2 x i32> zeroinitializer
-// CHECK: [[CNT:%[^ ]+]] = zext <2 x i32> [[T3]] to <2 x i64>
-// CHECK: %{{.*}} = lshr <2 x i64> [[VAL]], [[CNT]]
ul = ul >> cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = lshr <2 x i64> [[VAL]], <i64 5, i64 5>
ul = ul >> 5;
}
-void test_sr_assign (void)
-{
-// CHECK-LABEL: test_sr_assign
+// CHECK-LABEL: define void @test_sr_assign() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SHR:%.*]] = ashr <16 x i8> [[TMP1]], [[TMP0]]
+// CHECK: store volatile <16 x i8> [[SHR]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SHR1:%.*]] = ashr <16 x i8> [[TMP3]], [[TMP2]]
+// CHECK: store volatile <16 x i8> [[SHR1]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT:%.*]] = insertelement <16 x i32> undef, i32 [[TMP4]], i32 0
+// CHECK: [[SPLAT_SPLAT:%.*]] = shufflevector <16 x i32> [[SPLAT_SPLAT:%.*]]insert, <16 x i32> undef, <16 x i32> zeroinitializer
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SH_PROM:%.*]] = trunc <16 x i32> [[SPLAT_SPLAT]] to <16 x i8>
+// CHECK: [[SHR2:%.*]] = ashr <16 x i8> [[TMP5]], [[SH_PROM]]
+// CHECK: store volatile <16 x i8> [[SHR2]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[SHR3:%.*]] = ashr <16 x i8> [[TMP6]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+// CHECK: store volatile <16 x i8> [[SHR3]], <16 x i8>* @sc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SHR4:%.*]] = lshr <16 x i8> [[TMP8]], [[TMP7]]
+// CHECK: store volatile <16 x i8> [[SHR4]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SHR5:%.*]] = lshr <16 x i8> [[TMP10]], [[TMP9]]
+// CHECK: store volatile <16 x i8> [[SHR5]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <16 x i32> undef, i32 [[TMP11]], i32 0
+// CHECK: [[SPLAT_SPLAT7:%.*]] = shufflevector <16 x i32> [[SPLAT_SPLATINSERT6]], <16 x i32> undef, <16 x i32> zeroinitializer
+// CHECK: [[TMP12:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SH_PROM8:%.*]] = trunc <16 x i32> [[SPLAT_SPLAT7]] to <16 x i8>
+// CHECK: [[SHR9:%.*]] = lshr <16 x i8> [[TMP12]], [[SH_PROM8]]
+// CHECK: store volatile <16 x i8> [[SHR9]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[SHR10:%.*]] = lshr <16 x i8> [[TMP13]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
+// CHECK: store volatile <16 x i8> [[SHR10]], <16 x i8>* @uc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SHR11:%.*]] = ashr <8 x i16> [[TMP15]], [[TMP14]]
+// CHECK: store volatile <8 x i16> [[SHR11]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SHR12:%.*]] = ashr <8 x i16> [[TMP17]], [[TMP16]]
+// CHECK: store volatile <8 x i16> [[SHR12]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP18:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <8 x i32> undef, i32 [[TMP18]], i32 0
+// CHECK: [[SPLAT_SPLAT14:%.*]] = shufflevector <8 x i32> [[SPLAT_SPLATINSERT13]], <8 x i32> undef, <8 x i32> zeroinitializer
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SH_PROM15:%.*]] = trunc <8 x i32> [[SPLAT_SPLAT14]] to <8 x i16>
+// CHECK: [[SHR16:%.*]] = ashr <8 x i16> [[TMP19]], [[SH_PROM15]]
+// CHECK: store volatile <8 x i16> [[SHR16]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[SHR17:%.*]] = ashr <8 x i16> [[TMP20]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
+// CHECK: store volatile <8 x i16> [[SHR17]], <8 x i16>* @ss, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SHR18:%.*]] = lshr <8 x i16> [[TMP22]], [[TMP21]]
+// CHECK: store volatile <8 x i16> [[SHR18]], <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SHR19:%.*]] = lshr <8 x i16> [[TMP24]], [[TMP23]]
+// CHECK: store volatile <8 x i16> [[SHR19]], <8 x i16>* @us, align 8
+// CHECK: [[TMP25:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT20:%.*]] = insertelement <8 x i32> undef, i32 [[TMP25]], i32 0
+// CHECK: [[SPLAT_SPLAT21:%.*]] = shufflevector <8 x i32> [[SPLAT_SPLATINSERT20]], <8 x i32> undef, <8 x i32> zeroinitializer
+// CHECK: [[TMP26:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SH_PROM22:%.*]] = trunc <8 x i32> [[SPLAT_SPLAT21]] to <8 x i16>
+// CHECK: [[SHR23:%.*]] = lshr <8 x i16> [[TMP26]], [[SH_PROM22]]
+// CHECK: store volatile <8 x i16> [[SHR23]], <8 x i16>* @us, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[SHR24:%.*]] = lshr <8 x i16> [[TMP27]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
+// CHECK: store volatile <8 x i16> [[SHR24]], <8 x i16>* @us, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHR25:%.*]] = ashr <4 x i32> [[TMP29]], [[TMP28]]
+// CHECK: store volatile <4 x i32> [[SHR25]], <4 x i32>* @si, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHR26:%.*]] = ashr <4 x i32> [[TMP31]], [[TMP30]]
+// CHECK: store volatile <4 x i32> [[SHR26]], <4 x i32>* @si, align 8
+// CHECK: [[TMP32:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT27:%.*]] = insertelement <4 x i32> undef, i32 [[TMP32]], i32 0
+// CHECK: [[SPLAT_SPLAT28:%.*]] = shufflevector <4 x i32> [[SPLAT_SPLATINSERT27]], <4 x i32> undef, <4 x i32> zeroinitializer
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHR29:%.*]] = ashr <4 x i32> [[TMP33]], [[SPLAT_SPLAT28]]
+// CHECK: store volatile <4 x i32> [[SHR29]], <4 x i32>* @si, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[SHR30:%.*]] = ashr <4 x i32> [[TMP34]], <i32 5, i32 5, i32 5, i32 5>
+// CHECK: store volatile <4 x i32> [[SHR30]], <4 x i32>* @si, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHR31:%.*]] = lshr <4 x i32> [[TMP36]], [[TMP35]]
+// CHECK: store volatile <4 x i32> [[SHR31]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHR32:%.*]] = lshr <4 x i32> [[TMP38]], [[TMP37]]
+// CHECK: store volatile <4 x i32> [[SHR32]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP39:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT33:%.*]] = insertelement <4 x i32> undef, i32 [[TMP39]], i32 0
+// CHECK: [[SPLAT_SPLAT34:%.*]] = shufflevector <4 x i32> [[SPLAT_SPLATINSERT33]], <4 x i32> undef, <4 x i32> zeroinitializer
+// CHECK: [[TMP40:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHR35:%.*]] = lshr <4 x i32> [[TMP40]], [[SPLAT_SPLAT34]]
+// CHECK: store volatile <4 x i32> [[SHR35]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[SHR36:%.*]] = lshr <4 x i32> [[TMP41]], <i32 5, i32 5, i32 5, i32 5>
+// CHECK: store volatile <4 x i32> [[SHR36]], <4 x i32>* @ui, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SHR37:%.*]] = ashr <2 x i64> [[TMP43]], [[TMP42]]
+// CHECK: store volatile <2 x i64> [[SHR37]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SHR38:%.*]] = ashr <2 x i64> [[TMP45]], [[TMP44]]
+// CHECK: store volatile <2 x i64> [[SHR38]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT39:%.*]] = insertelement <2 x i32> undef, i32 [[TMP46]], i32 0
+// CHECK: [[SPLAT_SPLAT40:%.*]] = shufflevector <2 x i32> [[SPLAT_SPLATINSERT39]], <2 x i32> undef, <2 x i32> zeroinitializer
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SH_PROM41:%.*]] = zext <2 x i32> [[SPLAT_SPLAT40]] to <2 x i64>
+// CHECK: [[SHR42:%.*]] = ashr <2 x i64> [[TMP47]], [[SH_PROM41]]
+// CHECK: store volatile <2 x i64> [[SHR42]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[SHR43:%.*]] = ashr <2 x i64> [[TMP48]], <i64 5, i64 5>
+// CHECK: store volatile <2 x i64> [[SHR43]], <2 x i64>* @sl, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SHR44:%.*]] = lshr <2 x i64> [[TMP50]], [[TMP49]]
+// CHECK: store volatile <2 x i64> [[SHR44]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SHR45:%.*]] = lshr <2 x i64> [[TMP52]], [[TMP51]]
+// CHECK: store volatile <2 x i64> [[SHR45]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP53:%.*]] = load volatile i32, i32* @cnt, align 4
+// CHECK: [[SPLAT_SPLATINSERT46:%.*]] = insertelement <2 x i32> undef, i32 [[TMP53]], i32 0
+// CHECK: [[SPLAT_SPLAT47:%.*]] = shufflevector <2 x i32> [[SPLAT_SPLATINSERT46]], <2 x i32> undef, <2 x i32> zeroinitializer
+// CHECK: [[TMP54:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SH_PROM48:%.*]] = zext <2 x i32> [[SPLAT_SPLAT47]] to <2 x i64>
+// CHECK: [[SHR49:%.*]] = lshr <2 x i64> [[TMP54]], [[SH_PROM48]]
+// CHECK: store volatile <2 x i64> [[SHR49]], <2 x i64>* @ul, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[SHR50:%.*]] = lshr <2 x i64> [[TMP55]], <i64 5, i64 5>
+// CHECK: store volatile <2 x i64> [[SHR50]], <2 x i64>* @ul, align 8
+// CHECK: ret void
+void test_sr_assign(void) {
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = ashr <16 x i8> [[VAL]], [[CNT]]
sc >>= sc2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = ashr <16 x i8> [[VAL]], [[CNT]]
sc >>= uc2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <16 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <16 x i32> [[T2]], <16 x i32> undef, <16 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[CNT:%[^ ]+]] = trunc <16 x i32> [[T3]] to <16 x i8>
-// CHECK: %{{.*}} = ashr <16 x i8> [[VAL]], [[CNT]]
sc >>= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: %{{.*}} = ashr <16 x i8> [[VAL]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
sc >>= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = lshr <16 x i8> [[VAL]], [[CNT]]
uc >>= sc2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = lshr <16 x i8> [[VAL]], [[CNT]]
uc >>= uc2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <16 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <16 x i32> [[T2]], <16 x i32> undef, <16 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[CNT:%[^ ]+]] = trunc <16 x i32> [[T3]] to <16 x i8>
-// CHECK: %{{.*}} = lshr <16 x i8> [[VAL]], [[CNT]]
uc >>= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: %{{.*}} = lshr <16 x i8> [[VAL]], <i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5, i8 5>
uc >>= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = ashr <8 x i16> [[VAL]], [[CNT]]
ss >>= ss2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = ashr <8 x i16> [[VAL]], [[CNT]]
ss >>= us2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <8 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <8 x i32> [[T2]], <8 x i32> undef, <8 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[CNT:%[^ ]+]] = trunc <8 x i32> [[T3]] to <8 x i16>
-// CHECK: %{{.*}} = ashr <8 x i16> [[VAL]], [[CNT]]
ss >>= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: %{{.*}} = ashr <8 x i16> [[VAL]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
ss >>= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = lshr <8 x i16> [[VAL]], [[CNT]]
us >>= ss2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = lshr <8 x i16> [[VAL]], [[CNT]]
us >>= us2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <8 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <8 x i32> [[T2]], <8 x i32> undef, <8 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[CNT:%[^ ]+]] = trunc <8 x i32> [[T3]] to <8 x i16>
-// CHECK: %{{.*}} = lshr <8 x i16> [[VAL]], [[CNT]]
us >>= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: %{{.*}} = lshr <8 x i16> [[VAL]], <i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5, i16 5>
us >>= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = ashr <4 x i32> [[VAL]], [[CNT]]
si >>= si2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = ashr <4 x i32> [[VAL]], [[CNT]]
si >>= ui2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T3:%[^ ]+]] = insertelement <4 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[CNT:%[^ ]+]] = shufflevector <4 x i32> [[T3]], <4 x i32> undef, <4 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = ashr <4 x i32> [[VAL]], [[CNT]]
si >>= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: %{{.*}} = ashr <4 x i32> [[VAL]], <i32 5, i32 5, i32 5, i32 5>
si >>= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = lshr <4 x i32> [[VAL]], [[CNT]]
ui >>= si2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = lshr <4 x i32> [[VAL]], [[CNT]]
ui >>= ui2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T3:%[^ ]+]] = insertelement <4 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[CNT:%[^ ]+]] = shufflevector <4 x i32> [[T3]], <4 x i32> undef, <4 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = lshr <4 x i32> [[VAL]], [[CNT]]
ui >>= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: %{{.*}} = lshr <4 x i32> [[VAL]], <i32 5, i32 5, i32 5, i32 5>
ui >>= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = ashr <2 x i64> [[VAL]], [[CNT]]
sl >>= sl2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = ashr <2 x i64> [[VAL]], [[CNT]]
sl >>= ul2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <2 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <2 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[CNT:%[^ ]+]] = zext <2 x i32> [[T3]] to <2 x i64>
-// CHECK: %{{.*}} = ashr <2 x i64> [[VAL]], [[CNT]]
sl >>= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: %{{.*}} = ashr <2 x i64> [[VAL]], <i64 5, i64 5>
sl >>= 5;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = lshr <2 x i64> [[VAL]], [[CNT]]
ul >>= sl2;
-// CHECK: [[CNT:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = lshr <2 x i64> [[VAL]], [[CNT]]
ul >>= ul2;
-// CHECK: [[T1:%[^ ]+]] = load volatile i32, i32* @cnt
-// CHECK: [[T2:%[^ ]+]] = insertelement <2 x i32> undef, i32 [[T1]], i32 0
-// CHECK: [[T3:%[^ ]+]] = shufflevector <2 x i32> [[T2]], <2 x i32> undef, <2 x i32> zeroinitializer
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[CNT:%[^ ]+]] = zext <2 x i32> [[T3]] to <2 x i64>
-// CHECK: %{{.*}} = lshr <2 x i64> [[VAL]], [[CNT]]
ul >>= cnt;
-// CHECK: [[VAL:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: %{{.*}} = lshr <2 x i64> [[VAL]], <i64 5, i64 5>
ul >>= 5;
}
-void test_cmpeq (void)
-{
-// CHECK-LABEL: test_cmpeq
+// CHECK-LABEL: define void @test_cmpeq() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[CMP:%.*]] = icmp eq <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP1:%.*]] = icmp eq <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: [[SEXT2:%.*]] = sext <16 x i1> [[CMP1]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT2]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[CMP3:%.*]] = icmp eq <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: [[SEXT4:%.*]] = sext <16 x i1> [[CMP3]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[CMP5:%.*]] = icmp eq <16 x i8> [[TMP6]], [[TMP7]]
+// CHECK: [[SEXT6:%.*]] = sext <16 x i1> [[CMP5]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT6]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP7:%.*]] = icmp eq <16 x i8> [[TMP8]], [[TMP9]]
+// CHECK: [[SEXT8:%.*]] = sext <16 x i1> [[CMP7]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT8]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[CMP9:%.*]] = icmp eq <16 x i8> [[TMP10]], [[TMP11]]
+// CHECK: [[SEXT10:%.*]] = sext <16 x i1> [[CMP9]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT10]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP11:%.*]] = icmp eq <16 x i8> [[TMP12]], [[TMP13]]
+// CHECK: [[SEXT12:%.*]] = sext <16 x i1> [[CMP11]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT12]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[CMP13:%.*]] = icmp eq <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: [[SEXT14:%.*]] = sext <8 x i1> [[CMP13]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT14]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP15:%.*]] = icmp eq <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: [[SEXT16:%.*]] = sext <8 x i1> [[CMP15]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT16]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[CMP17:%.*]] = icmp eq <8 x i16> [[TMP18]], [[TMP19]]
+// CHECK: [[SEXT18:%.*]] = sext <8 x i1> [[CMP17]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT18]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[CMP19:%.*]] = icmp eq <8 x i16> [[TMP20]], [[TMP21]]
+// CHECK: [[SEXT20:%.*]] = sext <8 x i1> [[CMP19]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT20]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP21:%.*]] = icmp eq <8 x i16> [[TMP22]], [[TMP23]]
+// CHECK: [[SEXT22:%.*]] = sext <8 x i1> [[CMP21]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT22]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[CMP23:%.*]] = icmp eq <8 x i16> [[TMP24]], [[TMP25]]
+// CHECK: [[SEXT24:%.*]] = sext <8 x i1> [[CMP23]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT24]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP25:%.*]] = icmp eq <8 x i16> [[TMP26]], [[TMP27]]
+// CHECK: [[SEXT26:%.*]] = sext <8 x i1> [[CMP25]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT26]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[CMP27:%.*]] = icmp eq <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: [[SEXT28:%.*]] = sext <4 x i1> [[CMP27]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT28]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP29:%.*]] = icmp eq <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: [[SEXT30:%.*]] = sext <4 x i1> [[CMP29]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT30]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[CMP31:%.*]] = icmp eq <4 x i32> [[TMP32]], [[TMP33]]
+// CHECK: [[SEXT32:%.*]] = sext <4 x i1> [[CMP31]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT32]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[CMP33:%.*]] = icmp eq <4 x i32> [[TMP34]], [[TMP35]]
+// CHECK: [[SEXT34:%.*]] = sext <4 x i1> [[CMP33]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT34]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP35:%.*]] = icmp eq <4 x i32> [[TMP36]], [[TMP37]]
+// CHECK: [[SEXT36:%.*]] = sext <4 x i1> [[CMP35]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT36]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[CMP37:%.*]] = icmp eq <4 x i32> [[TMP38]], [[TMP39]]
+// CHECK: [[SEXT38:%.*]] = sext <4 x i1> [[CMP37]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT38]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP40:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP39:%.*]] = icmp eq <4 x i32> [[TMP40]], [[TMP41]]
+// CHECK: [[SEXT40:%.*]] = sext <4 x i1> [[CMP39]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT40]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[CMP41:%.*]] = icmp eq <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: [[SEXT42:%.*]] = sext <2 x i1> [[CMP41]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT42]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP43:%.*]] = icmp eq <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: [[SEXT44:%.*]] = sext <2 x i1> [[CMP43]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT44]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[CMP45:%.*]] = icmp eq <2 x i64> [[TMP46]], [[TMP47]]
+// CHECK: [[SEXT46:%.*]] = sext <2 x i1> [[CMP45]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT46]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[CMP47:%.*]] = icmp eq <2 x i64> [[TMP48]], [[TMP49]]
+// CHECK: [[SEXT48:%.*]] = sext <2 x i1> [[CMP47]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT48]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP49:%.*]] = icmp eq <2 x i64> [[TMP50]], [[TMP51]]
+// CHECK: [[SEXT50:%.*]] = sext <2 x i1> [[CMP49]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT50]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP53:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[CMP51:%.*]] = icmp eq <2 x i64> [[TMP52]], [[TMP53]]
+// CHECK: [[SEXT52:%.*]] = sext <2 x i1> [[CMP51]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT52]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP54:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP53:%.*]] = icmp eq <2 x i64> [[TMP54]], [[TMP55]]
+// CHECK: [[SEXT54:%.*]] = sext <2 x i1> [[CMP53]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT54]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP56:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP57:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[CMP55:%.*]] = fcmp oeq <2 x double> [[TMP56]], [[TMP57]]
+// CHECK: [[SEXT56:%.*]] = sext <2 x i1> [[CMP55]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT56]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_cmpeq(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = sc == sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = sc == bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc == sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = uc == uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = uc == bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc == uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc == bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = ss == ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = ss == bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs == ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = us == us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = us == bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs == us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs == bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = si == si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = si == bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi == si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = ui == ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = ui == bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi == ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi == bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = sl == sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = sl == bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl == sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = ul == ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = ul == bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl == ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp eq <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl == bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[CMP:%[^ ]+]] = fcmp oeq <2 x double> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = fd == fd2;
}
-void test_cmpne (void)
-{
-// CHECK-LABEL: test_cmpne
+// CHECK-LABEL: define void @test_cmpne() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[CMP:%.*]] = icmp ne <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP1:%.*]] = icmp ne <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: [[SEXT2:%.*]] = sext <16 x i1> [[CMP1]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT2]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[CMP3:%.*]] = icmp ne <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: [[SEXT4:%.*]] = sext <16 x i1> [[CMP3]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[CMP5:%.*]] = icmp ne <16 x i8> [[TMP6]], [[TMP7]]
+// CHECK: [[SEXT6:%.*]] = sext <16 x i1> [[CMP5]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT6]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP7:%.*]] = icmp ne <16 x i8> [[TMP8]], [[TMP9]]
+// CHECK: [[SEXT8:%.*]] = sext <16 x i1> [[CMP7]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT8]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[CMP9:%.*]] = icmp ne <16 x i8> [[TMP10]], [[TMP11]]
+// CHECK: [[SEXT10:%.*]] = sext <16 x i1> [[CMP9]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT10]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP11:%.*]] = icmp ne <16 x i8> [[TMP12]], [[TMP13]]
+// CHECK: [[SEXT12:%.*]] = sext <16 x i1> [[CMP11]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT12]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[CMP13:%.*]] = icmp ne <8 x i16> [[TMP14]], [[TMP15]]
+// CHECK: [[SEXT14:%.*]] = sext <8 x i1> [[CMP13]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT14]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP15:%.*]] = icmp ne <8 x i16> [[TMP16]], [[TMP17]]
+// CHECK: [[SEXT16:%.*]] = sext <8 x i1> [[CMP15]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT16]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[CMP17:%.*]] = icmp ne <8 x i16> [[TMP18]], [[TMP19]]
+// CHECK: [[SEXT18:%.*]] = sext <8 x i1> [[CMP17]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT18]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[CMP19:%.*]] = icmp ne <8 x i16> [[TMP20]], [[TMP21]]
+// CHECK: [[SEXT20:%.*]] = sext <8 x i1> [[CMP19]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT20]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP21:%.*]] = icmp ne <8 x i16> [[TMP22]], [[TMP23]]
+// CHECK: [[SEXT22:%.*]] = sext <8 x i1> [[CMP21]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT22]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[CMP23:%.*]] = icmp ne <8 x i16> [[TMP24]], [[TMP25]]
+// CHECK: [[SEXT24:%.*]] = sext <8 x i1> [[CMP23]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT24]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP26:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP27:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP25:%.*]] = icmp ne <8 x i16> [[TMP26]], [[TMP27]]
+// CHECK: [[SEXT26:%.*]] = sext <8 x i1> [[CMP25]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT26]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP28:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP29:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[CMP27:%.*]] = icmp ne <4 x i32> [[TMP28]], [[TMP29]]
+// CHECK: [[SEXT28:%.*]] = sext <4 x i1> [[CMP27]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT28]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP30:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP31:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP29:%.*]] = icmp ne <4 x i32> [[TMP30]], [[TMP31]]
+// CHECK: [[SEXT30:%.*]] = sext <4 x i1> [[CMP29]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT30]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP32:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP33:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[CMP31:%.*]] = icmp ne <4 x i32> [[TMP32]], [[TMP33]]
+// CHECK: [[SEXT32:%.*]] = sext <4 x i1> [[CMP31]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT32]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP34:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP35:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[CMP33:%.*]] = icmp ne <4 x i32> [[TMP34]], [[TMP35]]
+// CHECK: [[SEXT34:%.*]] = sext <4 x i1> [[CMP33]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT34]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP36:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP37:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP35:%.*]] = icmp ne <4 x i32> [[TMP36]], [[TMP37]]
+// CHECK: [[SEXT36:%.*]] = sext <4 x i1> [[CMP35]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT36]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP38:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP39:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[CMP37:%.*]] = icmp ne <4 x i32> [[TMP38]], [[TMP39]]
+// CHECK: [[SEXT38:%.*]] = sext <4 x i1> [[CMP37]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT38]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP40:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP41:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP39:%.*]] = icmp ne <4 x i32> [[TMP40]], [[TMP41]]
+// CHECK: [[SEXT40:%.*]] = sext <4 x i1> [[CMP39]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT40]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP42:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP43:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[CMP41:%.*]] = icmp ne <2 x i64> [[TMP42]], [[TMP43]]
+// CHECK: [[SEXT42:%.*]] = sext <2 x i1> [[CMP41]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT42]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP44:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP45:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP43:%.*]] = icmp ne <2 x i64> [[TMP44]], [[TMP45]]
+// CHECK: [[SEXT44:%.*]] = sext <2 x i1> [[CMP43]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT44]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP46:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP47:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[CMP45:%.*]] = icmp ne <2 x i64> [[TMP46]], [[TMP47]]
+// CHECK: [[SEXT46:%.*]] = sext <2 x i1> [[CMP45]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT46]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP48:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP49:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[CMP47:%.*]] = icmp ne <2 x i64> [[TMP48]], [[TMP49]]
+// CHECK: [[SEXT48:%.*]] = sext <2 x i1> [[CMP47]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT48]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP50:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP51:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP49:%.*]] = icmp ne <2 x i64> [[TMP50]], [[TMP51]]
+// CHECK: [[SEXT50:%.*]] = sext <2 x i1> [[CMP49]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT50]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP52:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP53:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[CMP51:%.*]] = icmp ne <2 x i64> [[TMP52]], [[TMP53]]
+// CHECK: [[SEXT52:%.*]] = sext <2 x i1> [[CMP51]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT52]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP54:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP55:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP53:%.*]] = icmp ne <2 x i64> [[TMP54]], [[TMP55]]
+// CHECK: [[SEXT54:%.*]] = sext <2 x i1> [[CMP53]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT54]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP56:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP57:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[CMP55:%.*]] = fcmp une <2 x double> [[TMP56]], [[TMP57]]
+// CHECK: [[SEXT56:%.*]] = sext <2 x i1> [[CMP55]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT56]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_cmpne(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = sc != sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = sc != bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc != sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = uc != uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = uc != bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc != uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc != bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = ss != ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = ss != bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs != ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = us != us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = us != bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs != us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs != bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = si != si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = si != bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi != si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = ui != ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = ui != bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi != ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi != bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = sl != sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = sl != bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl != sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = ul != ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = ul != bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl != ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp ne <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl != bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[CMP:%[^ ]+]] = fcmp une <2 x double> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = fd != fd2;
}
-void test_cmpge (void)
-{
-// CHECK-LABEL: test_cmpge
+// CHECK-LABEL: define void @test_cmpge() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[CMP:%.*]] = icmp sge <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[CMP1:%.*]] = icmp uge <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: [[SEXT2:%.*]] = sext <16 x i1> [[CMP1]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT2]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP3:%.*]] = icmp uge <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: [[SEXT4:%.*]] = sext <16 x i1> [[CMP3]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[CMP5:%.*]] = icmp sge <8 x i16> [[TMP6]], [[TMP7]]
+// CHECK: [[SEXT6:%.*]] = sext <8 x i1> [[CMP5]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT6]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[CMP7:%.*]] = icmp uge <8 x i16> [[TMP8]], [[TMP9]]
+// CHECK: [[SEXT8:%.*]] = sext <8 x i1> [[CMP7]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT8]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP9:%.*]] = icmp uge <8 x i16> [[TMP10]], [[TMP11]]
+// CHECK: [[SEXT10:%.*]] = sext <8 x i1> [[CMP9]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT10]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[CMP11:%.*]] = icmp sge <4 x i32> [[TMP12]], [[TMP13]]
+// CHECK: [[SEXT12:%.*]] = sext <4 x i1> [[CMP11]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT12]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[CMP13:%.*]] = icmp uge <4 x i32> [[TMP14]], [[TMP15]]
+// CHECK: [[SEXT14:%.*]] = sext <4 x i1> [[CMP13]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT14]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP15:%.*]] = icmp uge <4 x i32> [[TMP16]], [[TMP17]]
+// CHECK: [[SEXT16:%.*]] = sext <4 x i1> [[CMP15]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT16]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[CMP17:%.*]] = icmp sge <2 x i64> [[TMP18]], [[TMP19]]
+// CHECK: [[SEXT18:%.*]] = sext <2 x i1> [[CMP17]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT18]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[CMP19:%.*]] = icmp uge <2 x i64> [[TMP20]], [[TMP21]]
+// CHECK: [[SEXT20:%.*]] = sext <2 x i1> [[CMP19]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT20]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP21:%.*]] = icmp uge <2 x i64> [[TMP22]], [[TMP23]]
+// CHECK: [[SEXT22:%.*]] = sext <2 x i1> [[CMP21]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT22]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[CMP23:%.*]] = fcmp oge <2 x double> [[TMP24]], [[TMP25]]
+// CHECK: [[SEXT24:%.*]] = sext <2 x i1> [[CMP23]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT24]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_cmpge(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[CMP:%[^ ]+]] = icmp sge <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = sc >= sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[CMP:%[^ ]+]] = icmp uge <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = uc >= uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp uge <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc >= bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[CMP:%[^ ]+]] = icmp sge <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = ss >= ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[CMP:%[^ ]+]] = icmp uge <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = us >= us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp uge <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs >= bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[CMP:%[^ ]+]] = icmp sge <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = si >= si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[CMP:%[^ ]+]] = icmp uge <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = ui >= ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp uge <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi >= bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[CMP:%[^ ]+]] = icmp sge <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = sl >= sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[CMP:%[^ ]+]] = icmp uge <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = ul >= ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp uge <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl >= bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[CMP:%[^ ]+]] = fcmp oge <2 x double> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = fd >= fd2;
}
-void test_cmpgt (void)
-{
-// CHECK-LABEL: test_cmpgt
+// CHECK-LABEL: define void @test_cmpgt() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[CMP:%.*]] = icmp sgt <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[CMP1:%.*]] = icmp ugt <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: [[SEXT2:%.*]] = sext <16 x i1> [[CMP1]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT2]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP3:%.*]] = icmp ugt <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: [[SEXT4:%.*]] = sext <16 x i1> [[CMP3]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[CMP5:%.*]] = icmp sgt <8 x i16> [[TMP6]], [[TMP7]]
+// CHECK: [[SEXT6:%.*]] = sext <8 x i1> [[CMP5]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT6]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[CMP7:%.*]] = icmp ugt <8 x i16> [[TMP8]], [[TMP9]]
+// CHECK: [[SEXT8:%.*]] = sext <8 x i1> [[CMP7]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT8]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP9:%.*]] = icmp ugt <8 x i16> [[TMP10]], [[TMP11]]
+// CHECK: [[SEXT10:%.*]] = sext <8 x i1> [[CMP9]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT10]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[CMP11:%.*]] = icmp sgt <4 x i32> [[TMP12]], [[TMP13]]
+// CHECK: [[SEXT12:%.*]] = sext <4 x i1> [[CMP11]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT12]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[CMP13:%.*]] = icmp ugt <4 x i32> [[TMP14]], [[TMP15]]
+// CHECK: [[SEXT14:%.*]] = sext <4 x i1> [[CMP13]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT14]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP15:%.*]] = icmp ugt <4 x i32> [[TMP16]], [[TMP17]]
+// CHECK: [[SEXT16:%.*]] = sext <4 x i1> [[CMP15]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT16]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[CMP17:%.*]] = icmp sgt <2 x i64> [[TMP18]], [[TMP19]]
+// CHECK: [[SEXT18:%.*]] = sext <2 x i1> [[CMP17]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT18]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[CMP19:%.*]] = icmp ugt <2 x i64> [[TMP20]], [[TMP21]]
+// CHECK: [[SEXT20:%.*]] = sext <2 x i1> [[CMP19]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT20]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP21:%.*]] = icmp ugt <2 x i64> [[TMP22]], [[TMP23]]
+// CHECK: [[SEXT22:%.*]] = sext <2 x i1> [[CMP21]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT22]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[CMP23:%.*]] = fcmp ogt <2 x double> [[TMP24]], [[TMP25]]
+// CHECK: [[SEXT24:%.*]] = sext <2 x i1> [[CMP23]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT24]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_cmpgt(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[CMP:%[^ ]+]] = icmp sgt <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = sc > sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ugt <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = uc > uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ugt <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc > bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[CMP:%[^ ]+]] = icmp sgt <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = ss > ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[CMP:%[^ ]+]] = icmp ugt <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = us > us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp ugt <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs > bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[CMP:%[^ ]+]] = icmp sgt <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = si > si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[CMP:%[^ ]+]] = icmp ugt <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = ui > ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp ugt <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi > bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[CMP:%[^ ]+]] = icmp sgt <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = sl > sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[CMP:%[^ ]+]] = icmp ugt <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = ul > ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp ugt <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl > bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[CMP:%[^ ]+]] = fcmp ogt <2 x double> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = fd > fd2;
}
-void test_cmple (void)
-{
-// CHECK-LABEL: test_cmple
+// CHECK-LABEL: define void @test_cmple() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[CMP:%.*]] = icmp sle <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[CMP1:%.*]] = icmp ule <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: [[SEXT2:%.*]] = sext <16 x i1> [[CMP1]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT2]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP3:%.*]] = icmp ule <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: [[SEXT4:%.*]] = sext <16 x i1> [[CMP3]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[CMP5:%.*]] = icmp sle <8 x i16> [[TMP6]], [[TMP7]]
+// CHECK: [[SEXT6:%.*]] = sext <8 x i1> [[CMP5]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT6]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[CMP7:%.*]] = icmp ule <8 x i16> [[TMP8]], [[TMP9]]
+// CHECK: [[SEXT8:%.*]] = sext <8 x i1> [[CMP7]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT8]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP9:%.*]] = icmp ule <8 x i16> [[TMP10]], [[TMP11]]
+// CHECK: [[SEXT10:%.*]] = sext <8 x i1> [[CMP9]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT10]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[CMP11:%.*]] = icmp sle <4 x i32> [[TMP12]], [[TMP13]]
+// CHECK: [[SEXT12:%.*]] = sext <4 x i1> [[CMP11]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT12]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[CMP13:%.*]] = icmp ule <4 x i32> [[TMP14]], [[TMP15]]
+// CHECK: [[SEXT14:%.*]] = sext <4 x i1> [[CMP13]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT14]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP15:%.*]] = icmp ule <4 x i32> [[TMP16]], [[TMP17]]
+// CHECK: [[SEXT16:%.*]] = sext <4 x i1> [[CMP15]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT16]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[CMP17:%.*]] = icmp sle <2 x i64> [[TMP18]], [[TMP19]]
+// CHECK: [[SEXT18:%.*]] = sext <2 x i1> [[CMP17]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT18]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[CMP19:%.*]] = icmp ule <2 x i64> [[TMP20]], [[TMP21]]
+// CHECK: [[SEXT20:%.*]] = sext <2 x i1> [[CMP19]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT20]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP21:%.*]] = icmp ule <2 x i64> [[TMP22]], [[TMP23]]
+// CHECK: [[SEXT22:%.*]] = sext <2 x i1> [[CMP21]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT22]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[CMP23:%.*]] = fcmp ole <2 x double> [[TMP24]], [[TMP25]]
+// CHECK: [[SEXT24:%.*]] = sext <2 x i1> [[CMP23]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT24]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_cmple(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[CMP:%[^ ]+]] = icmp sle <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = sc <= sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ule <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = uc <= uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ule <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc <= bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[CMP:%[^ ]+]] = icmp sle <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = ss <= ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[CMP:%[^ ]+]] = icmp ule <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = us <= us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp ule <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs <= bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[CMP:%[^ ]+]] = icmp sle <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = si <= si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[CMP:%[^ ]+]] = icmp ule <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = ui <= ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp ule <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi <= bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[CMP:%[^ ]+]] = icmp sle <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = sl <= sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[CMP:%[^ ]+]] = icmp ule <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = ul <= ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp ule <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl <= bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[CMP:%[^ ]+]] = fcmp ole <2 x double> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = fd <= fd2;
}
-void test_cmplt (void)
-{
-// CHECK-LABEL: test_cmplt
+// CHECK-LABEL: define void @test_cmplt() #0 {
+// CHECK: [[TMP0:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc, align 8
+// CHECK: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* @sc2, align 8
+// CHECK: [[CMP:%.*]] = icmp slt <16 x i8> [[TMP0]], [[TMP1]]
+// CHECK: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP2:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc, align 8
+// CHECK: [[TMP3:%.*]] = load volatile <16 x i8>, <16 x i8>* @uc2, align 8
+// CHECK: [[CMP1:%.*]] = icmp ult <16 x i8> [[TMP2]], [[TMP3]]
+// CHECK: [[SEXT2:%.*]] = sext <16 x i1> [[CMP1]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT2]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP4:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc, align 8
+// CHECK: [[TMP5:%.*]] = load volatile <16 x i8>, <16 x i8>* @bc2, align 8
+// CHECK: [[CMP3:%.*]] = icmp ult <16 x i8> [[TMP4]], [[TMP5]]
+// CHECK: [[SEXT4:%.*]] = sext <16 x i1> [[CMP3]] to <16 x i8>
+// CHECK: store volatile <16 x i8> [[SEXT4]], <16 x i8>* @bc, align 8
+// CHECK: [[TMP6:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss, align 8
+// CHECK: [[TMP7:%.*]] = load volatile <8 x i16>, <8 x i16>* @ss2, align 8
+// CHECK: [[CMP5:%.*]] = icmp slt <8 x i16> [[TMP6]], [[TMP7]]
+// CHECK: [[SEXT6:%.*]] = sext <8 x i1> [[CMP5]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT6]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP8:%.*]] = load volatile <8 x i16>, <8 x i16>* @us, align 8
+// CHECK: [[TMP9:%.*]] = load volatile <8 x i16>, <8 x i16>* @us2, align 8
+// CHECK: [[CMP7:%.*]] = icmp ult <8 x i16> [[TMP8]], [[TMP9]]
+// CHECK: [[SEXT8:%.*]] = sext <8 x i1> [[CMP7]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT8]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP10:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs, align 8
+// CHECK: [[TMP11:%.*]] = load volatile <8 x i16>, <8 x i16>* @bs2, align 8
+// CHECK: [[CMP9:%.*]] = icmp ult <8 x i16> [[TMP10]], [[TMP11]]
+// CHECK: [[SEXT10:%.*]] = sext <8 x i1> [[CMP9]] to <8 x i16>
+// CHECK: store volatile <8 x i16> [[SEXT10]], <8 x i16>* @bs, align 8
+// CHECK: [[TMP12:%.*]] = load volatile <4 x i32>, <4 x i32>* @si, align 8
+// CHECK: [[TMP13:%.*]] = load volatile <4 x i32>, <4 x i32>* @si2, align 8
+// CHECK: [[CMP11:%.*]] = icmp slt <4 x i32> [[TMP12]], [[TMP13]]
+// CHECK: [[SEXT12:%.*]] = sext <4 x i1> [[CMP11]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT12]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP14:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui, align 8
+// CHECK: [[TMP15:%.*]] = load volatile <4 x i32>, <4 x i32>* @ui2, align 8
+// CHECK: [[CMP13:%.*]] = icmp ult <4 x i32> [[TMP14]], [[TMP15]]
+// CHECK: [[SEXT14:%.*]] = sext <4 x i1> [[CMP13]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT14]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP16:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi, align 8
+// CHECK: [[TMP17:%.*]] = load volatile <4 x i32>, <4 x i32>* @bi2, align 8
+// CHECK: [[CMP15:%.*]] = icmp ult <4 x i32> [[TMP16]], [[TMP17]]
+// CHECK: [[SEXT16:%.*]] = sext <4 x i1> [[CMP15]] to <4 x i32>
+// CHECK: store volatile <4 x i32> [[SEXT16]], <4 x i32>* @bi, align 8
+// CHECK: [[TMP18:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl, align 8
+// CHECK: [[TMP19:%.*]] = load volatile <2 x i64>, <2 x i64>* @sl2, align 8
+// CHECK: [[CMP17:%.*]] = icmp slt <2 x i64> [[TMP18]], [[TMP19]]
+// CHECK: [[SEXT18:%.*]] = sext <2 x i1> [[CMP17]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT18]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP20:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul, align 8
+// CHECK: [[TMP21:%.*]] = load volatile <2 x i64>, <2 x i64>* @ul2, align 8
+// CHECK: [[CMP19:%.*]] = icmp ult <2 x i64> [[TMP20]], [[TMP21]]
+// CHECK: [[SEXT20:%.*]] = sext <2 x i1> [[CMP19]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT20]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP22:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl, align 8
+// CHECK: [[TMP23:%.*]] = load volatile <2 x i64>, <2 x i64>* @bl2, align 8
+// CHECK: [[CMP21:%.*]] = icmp ult <2 x i64> [[TMP22]], [[TMP23]]
+// CHECK: [[SEXT22:%.*]] = sext <2 x i1> [[CMP21]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT22]], <2 x i64>* @bl, align 8
+// CHECK: [[TMP24:%.*]] = load volatile <2 x double>, <2 x double>* @fd, align 8
+// CHECK: [[TMP25:%.*]] = load volatile <2 x double>, <2 x double>* @fd2, align 8
+// CHECK: [[CMP23:%.*]] = fcmp olt <2 x double> [[TMP24]], [[TMP25]]
+// CHECK: [[SEXT24:%.*]] = sext <2 x i1> [[CMP23]] to <2 x i64>
+// CHECK: store volatile <2 x i64> [[SEXT24]], <2 x i64>* @bl, align 8
+// CHECK: ret void
+void test_cmplt(void) {
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @sc2
-// CHECK: [[CMP:%[^ ]+]] = icmp slt <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = sc < sc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @uc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ult <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = uc < uc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <16 x i8>, <16 x i8>* @bc2
-// CHECK: [[CMP:%[^ ]+]] = icmp ult <16 x i8> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <16 x i1> [[CMP]] to <16 x i8>
bc = bc < bc2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @ss2
-// CHECK: [[CMP:%[^ ]+]] = icmp slt <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = ss < ss2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @us2
-// CHECK: [[CMP:%[^ ]+]] = icmp ult <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = us < us2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <8 x i16>, <8 x i16>* @bs2
-// CHECK: [[CMP:%[^ ]+]] = icmp ult <8 x i16> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <8 x i1> [[CMP]] to <8 x i16>
bs = bs < bs2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @si2
-// CHECK: [[CMP:%[^ ]+]] = icmp slt <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = si < si2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @ui2
-// CHECK: [[CMP:%[^ ]+]] = icmp ult <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = ui < ui2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x i32>, <4 x i32>* @bi2
-// CHECK: [[CMP:%[^ ]+]] = icmp ult <4 x i32> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
bi = bi < bi2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @sl2
-// CHECK: [[CMP:%[^ ]+]] = icmp slt <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = sl < sl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @ul2
-// CHECK: [[CMP:%[^ ]+]] = icmp ult <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = ul < ul2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x i64>, <2 x i64>* @bl2
-// CHECK: [[CMP:%[^ ]+]] = icmp ult <2 x i64> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = bl < bl2;
-// CHECK: [[VAL1:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd
-// CHECK: [[VAL2:%[^ ]+]] = load volatile <2 x double>, <2 x double>* @fd2
-// CHECK: [[CMP:%[^ ]+]] = fcmp olt <2 x double> [[VAL1]], [[VAL2]]
-// CHECK: %{{.*}} = sext <2 x i1> [[CMP]] to <2 x i64>
bl = fd < fd2;
}
diff --git a/test/CodeGenCUDA/fp-contract.cu b/test/CodeGenCUDA/fp-contract.cu
index 070ebaea44ee..96de5c451b02 100644
--- a/test/CodeGenCUDA/fp-contract.cu
+++ b/test/CodeGenCUDA/fp-contract.cu
@@ -10,10 +10,10 @@
// RUN: -ffp-contract=fast -disable-llvm-passes -o - %s \
// RUN: | FileCheck -check-prefix ENABLED %s
-// Explicit -ffp-contract=on -- fusing by front-end (disabled).
+// Explicit -ffp-contract=on -- fusing by front-end.
// RUN: %clang_cc1 -fcuda-is-device -triple nvptx-nvidia-cuda -S \
// RUN: -ffp-contract=on -disable-llvm-passes -o - %s \
-// RUN: | FileCheck -check-prefix DISABLED %s
+// RUN: | FileCheck -check-prefix ENABLED %s
// Explicit -ffp-contract=off should disable instruction fusing.
// RUN: %clang_cc1 -fcuda-is-device -triple nvptx-nvidia-cuda -S \
diff --git a/test/CodeGenCUDA/propagate-metadata.cu b/test/CodeGenCUDA/propagate-metadata.cu
new file mode 100644
index 000000000000..f8db765099ef
--- /dev/null
+++ b/test/CodeGenCUDA/propagate-metadata.cu
@@ -0,0 +1,62 @@
+// Check that when we link a bitcode module into a file using
+// -mlink-cuda-bitcode, we apply the same attributes to the functions in that
+// bitcode module as we apply to functions we generate.
+//
+// In particular, we check that ftz and unsafe-math are propagated into the
+// bitcode library as appropriate.
+//
+// In addition, we set -ftrapping-math on the bitcode library, but then set
+// -fno-trapping-math on the main compilations, and ensure that the latter flag
+// overrides the flag on the bitcode library.
+
+// Build the bitcode library. This is not built in CUDA mode, otherwise it
+// might have incompatible attributes. This mirrors how libdevice is built.
+// RUN: %clang_cc1 -x c++ -emit-llvm-bc -ftrapping-math -DLIB \
+// RUN: %s -o %t.bc -triple nvptx-unknown-unknown
+
+// RUN: %clang_cc1 -x cuda %s -emit-llvm -mlink-cuda-bitcode %t.bc -o - \
+// RUN: -fno-trapping-math -fcuda-is-device -triple nvptx-unknown-unknown \
+// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=NOFTZ --check-prefix=NOFAST
+
+// RUN: %clang_cc1 -x cuda %s -emit-llvm -mlink-cuda-bitcode %t.bc \
+// RUN: -fno-trapping-math -fcuda-flush-denormals-to-zero -o - \
+// RUN: -fcuda-is-device -triple nvptx-unknown-unknown \
+// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=FTZ \
+// RUN: --check-prefix=NOFAST
+
+// RUN: %clang_cc1 -x cuda %s -emit-llvm -mlink-cuda-bitcode %t.bc \
+// RUN: -fno-trapping-math -fcuda-flush-denormals-to-zero -o - \
+// RUN: -fcuda-is-device -menable-unsafe-fp-math -triple nvptx-unknown-unknown \
+// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=FAST
+
+// Wrap everything in extern "C" so we don't ahve to worry about name mangling
+// in the IR.
+extern "C" {
+#ifdef LIB
+
+// This function is defined in the library and only declared in the main
+// compilation.
+void lib_fn() {}
+
+#else
+
+#include "Inputs/cuda.h"
+__device__ void lib_fn();
+__global__ void kernel() { lib_fn(); }
+
+#endif
+}
+
+// The kernel and lib function should have the same attributes.
+// CHECK: define void @kernel() [[attr:#[0-9]+]]
+// CHECK: define internal void @lib_fn() [[attr]]
+
+// Check the attribute list.
+// CHECK: attributes [[attr]] = {
+// CHECK: "no-trapping-math"="true"
+
+// FTZ-SAME: "nvptx-f32ftz"="true"
+// NOFTZ-NOT: "nvptx-f32ftz"="true"
+
+// FAST-SAME: "unsafe-fp-math"="true"
+// NOFAST-NOT: "unsafe-fp-math"="true"
diff --git a/test/CodeGenCXX/atomic-dllexport.cpp b/test/CodeGenCXX/atomic-dllexport.cpp
new file mode 100644
index 000000000000..ae1422243160
--- /dev/null
+++ b/test/CodeGenCXX/atomic-dllexport.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++11 -fms-extensions -O0 -o - %s | FileCheck --check-prefix=M32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c++11 -fms-extensions -O0 -o - %s | FileCheck --check-prefix=M64 %s
+
+struct __declspec(dllexport) SomeStruct {
+ // Copy assignment operator should be produced, and exported:
+ // M32: define weak_odr dllexport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.SomeStruct* @"\01??4SomeStruct@@QAEAAU0@ABU0@@Z"
+ // M64: define weak_odr dllexport dereferenceable({{[0-9]+}}) %struct.SomeStruct* @"\01??4SomeStruct@@QEAAAEAU0@AEBU0@@Z"
+ _Atomic(int) mData;
+};
diff --git a/test/CodeGenCXX/cfi-ms-rtti.cpp b/test/CodeGenCXX/cfi-ms-rtti.cpp
index fbebad4b1b8d..328297d85c12 100644
--- a/test/CodeGenCXX/cfi-ms-rtti.cpp
+++ b/test/CodeGenCXX/cfi-ms-rtti.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -flto -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall | FileCheck --check-prefix=RTTI %s
-// RUN: %clang_cc1 -flto -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall -fno-rtti-data | FileCheck --check-prefix=NO-RTTI %s
+// RUN: %clang_cc1 -flto -flto-unit -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall | FileCheck --check-prefix=RTTI %s
+// RUN: %clang_cc1 -flto -flto-unit -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall -fno-rtti-data | FileCheck --check-prefix=NO-RTTI %s
struct A {
A();
diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp
index ecbe5bb45b63..a89814038340 100644
--- a/test/CodeGenCXX/constructors.cpp
+++ b/test/CodeGenCXX/constructors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s --implicit-check-not=should_not_appear_in_output
struct Member { int x; Member(); Member(int); Member(const Member &); };
struct VBase { int x; VBase(); VBase(int); VBase(const VBase &); };
@@ -109,3 +109,57 @@ namespace test1 {
// CHECK: [[THIS:%.*]] = load [[B:%.*]]*, [[B:%.*]]**
// CHECK-NEXT: ret void
}
+
+// Ensure that we
+// a) emit the ABI-required but useless complete object and deleting destructor
+// symbols for an abstract class, and
+// b) do *not* emit references to virtual base destructors for an abstract class
+//
+// Our approach to this is to give these functions a body that simply traps.
+//
+// FIXME: We should ideally not create these symbols at all, but Clang can
+// actually generate references to them in other TUs in some cases, so we can't
+// stop emitting them without breaking ABI. See:
+//
+// https://github.com/itanium-cxx-abi/cxx-abi/issues/10
+namespace abstract {
+ // Note, the destructor of this class is not instantiated here.
+ template<typename T> struct should_not_appear_in_output {
+ ~should_not_appear_in_output() { int arr[-(int)sizeof(T)]; }
+ };
+
+ struct X { ~X(); };
+
+ struct A : virtual should_not_appear_in_output<int>, X {
+ virtual ~A() = 0;
+ };
+
+ // CHECK-LABEL: define void @_ZN8abstract1AD2Ev(
+ // CHECK: call {{.*}}@_ZN8abstract1XD2Ev(
+ // CHECK: ret
+
+ // CHECK-LABEL: define void @_ZN8abstract1AD1Ev(
+ // CHECK: call {{.*}}@llvm.trap(
+ // CHECK: unreachable
+
+ // CHECK-LABEL: define void @_ZN8abstract1AD0Ev(
+ // CHECK: call {{.*}}@llvm.trap(
+ // CHECK: unreachable
+ A::~A() {}
+
+ struct B : virtual should_not_appear_in_output<int>, X {
+ virtual void f() = 0;
+ ~B();
+ };
+
+ // CHECK-LABEL: define void @_ZN8abstract1BD2Ev(
+ // CHECK: call {{.*}}@_ZN8abstract1XD2Ev(
+ // CHECK: ret
+
+ // CHECK-LABEL: define void @_ZN8abstract1BD1Ev(
+ // CHECK: call {{.*}}@llvm.trap(
+ // CHECK: unreachable
+
+ // CHECK-NOT: @_ZN8abstract1BD0Ev(
+ B::~B() {}
+}
diff --git a/test/CodeGenCXX/cxx11-initializer-aggregate.cpp b/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
index be4fd73e6c21..8bf35966f5b9 100644
--- a/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ b/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -2,7 +2,16 @@
struct A { int a, b; int f(); };
-// CHECK: define {{.*}}@_Z3fn1i(
+namespace NonAggregateCopyInAggregateInit { // PR32044
+ struct A { constexpr A(int n) : x(n), y() {} int x, y; } extern a;
+ // CHECK-DAG: @_ZN31NonAggregateCopyInAggregateInit1bE = global %{{.*}} { %[[A:.*]]* @_ZN31NonAggregateCopyInAggregateInit1aE }
+ struct B { A &p; } b{{a}};
+ // CHECK-DAG: @_ZGRN31NonAggregateCopyInAggregateInit1cE_ = internal global %[[A]] { i32 1, i32 0 }
+ // CHECK-DAG: @_ZN31NonAggregateCopyInAggregateInit1cE = global %{{.*}} { %{{.*}}* @_ZGRN31NonAggregateCopyInAggregateInit1cE_ }
+ struct C { A &&p; } c{{1}};
+}
+
+// CHECK-LABEL: define {{.*}}@_Z3fn1i(
int fn1(int x) {
// CHECK: %[[INITLIST:.*]] = alloca %struct.A
// CHECK: %[[A:.*]] = getelementptr inbounds %struct.A, %struct.A* %[[INITLIST]], i32 0, i32 0
@@ -15,7 +24,7 @@ int fn1(int x) {
struct B { int &r; int &f() { return r; } };
-// CHECK: define {{.*}}@_Z3fn2Ri(
+// CHECK-LABEL: define {{.*}}@_Z3fn2Ri(
int &fn2(int &v) {
// CHECK: %[[INITLIST2:.*]] = alloca %struct.B, align 8
// CHECK: %[[R:.*]] = getelementptr inbounds %struct.B, %struct.B* %[[INITLIST2:.*]], i32 0, i32 0
@@ -24,7 +33,7 @@ int &fn2(int &v) {
return B{v}.f();
}
-// CHECK: define {{.*}}@__cxx_global_var_init(
+// CHECK-LABEL: define {{.*}}@__cxx_global_var_init(
//
// CHECK: call {{.*}}@_ZN14NonTrivialInit1AC1Ev(
// CHECK: getelementptr inbounds {{.*}}, i64 1
diff --git a/test/CodeGenCXX/debug-info-class-optzns.cpp b/test/CodeGenCXX/debug-info-class-optzns.cpp
new file mode 100644
index 000000000000..d58510b7155a
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-class-optzns.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-unknown_unknown -emit-llvm -debug-info-kind=limited %s -O1 -o - | FileCheck %s
+
+// Ensure class definitions are not emitted to debug info just because the
+// vtable is emitted for optimization purposes (as available_externally). The
+// class definition debug info should only go where the vtable is actually
+// emitted into the object file.
+
+// CHECK: @_ZTV3foo = available_externally
+
+// Verify that this doesn't involve querying for the vtable of types that aren't
+// dynamic (that would cause an assertion in the case below)
+
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "bar<int>"
+template <typename> struct bar {};
+extern template struct bar<int>;
+bar<int> *p1;
+bar<int> a;
+
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
+// CHECK-SAME: DIFlagFwdDecl
+
+struct foo {
+ virtual void f();
+};
+
+foo f;
diff --git a/test/CodeGenCXX/debug-info-inheriting-constructor.cpp b/test/CodeGenCXX/debug-info-inheriting-constructor.cpp
new file mode 100644
index 000000000000..e3708e2080f0
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-inheriting-constructor.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -debug-info-kind=standalone -std=c++11 -triple x86_64-darwin -emit-llvm -o - %s | FileCheck %s
+
+struct A {
+ A(int, ...);
+};
+struct B : A {
+ using A::A;
+};
+
+A::A(int i, ...) {}
+// CHECK: define void @{{.*}}foo
+// CHECK-NOT ret void
+// CHECK: call void @llvm.dbg.declare
+// CHECK-NOT ret void
+// CHECK: call void @llvm.dbg.declare(metadata %{{.*}}** %{{[^,]+}},
+// CHECK-SAME: metadata ![[THIS:[0-9]+]], metadata !{{[0-9]+}}), !dbg ![[LOC:[0-9]+]]
+// CHECK: ret void, !dbg ![[NOINL:[0-9]+]]
+// CHECK: ![[FOO:.*]] = distinct !DISubprogram(name: "foo"
+// CHECK-DAG: ![[A:.*]] = distinct !DISubprogram(name: "A", linkageName: "_ZN1BCI11AEiz"
+void foo() {
+// CHECK-DAG: ![[LOC]] = !DILocation(line: 0, scope: ![[A]], inlinedAt: ![[INL:[0-9]+]])
+// CHECK-DAG: ![[INL]] = !DILocation(line: [[@LINE+1]], scope: ![[FOO]])
+ B b(0);
+// CHECK: ![[NOINL]] = !DILocation(line: [[@LINE+1]], scope: !{{[0-9]+}})
+}
diff --git a/test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp b/test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp
new file mode 100644
index 000000000000..f876267eb5d6
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple i686--windows -emit-llvm -debug-info-kind=line-tables-only -x c++ %s -fms-extensions -o - | FileCheck %s
+
+struct __declspec(dllexport) S { virtual ~S(); };
+struct __declspec(dllexport) T { virtual ~T(); };
+struct __declspec(dllexport) U : S, T { virtual ~U(); };
+
+// CHECK-LABEL: define {{.*}} @"\01??_GS@@UAEPAXI@Z"
+// CHECK: call x86_thiscallcc void @"\01??_DS@@QAEXXZ"(%struct.S* %this1){{.*}}!dbg !{{[0-9]+}}
+
+// CHECK-LABEL: define {{.*}} @"\01??_GT@@UAEPAXI@Z"
+// CHECK: call x86_thiscallcc void @"\01??_DT@@QAEXXZ"(%struct.T* %this1){{.*}}!dbg !{{[0-9]+}}
+
+// CHECK-LABEL: define {{.*}} @"\01??_GU@@UAEPAXI@Z"
+// CHECK: call x86_thiscallcc void @"\01??_DU@@QAEXXZ"(%struct.U* %this1){{.*}}!dbg !{{[0-9]+}}
diff --git a/test/CodeGenCXX/debug-info-template-deduction-guide.cpp b/test/CodeGenCXX/debug-info-template-deduction-guide.cpp
new file mode 100644
index 000000000000..26eb2156e627
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-template-deduction-guide.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang -S -emit-llvm -target x86_64-unknown_unknown -g %s -o - -std=c++1z | FileCheck %s
+
+// Verify that we don't crash when emitting debug information for objects
+// created from a deduced template specialization.
+
+template <class T>
+struct S {
+ S(T) {}
+};
+
+// CHECK: !DIGlobalVariable(name: "s1"
+// CHECK-SAME: type: [[TYPE_NUM:![0-9]+]]
+// CHECK: !DIGlobalVariable(name: "s2"
+// CHECK-SAME: type: [[TYPE_NUM]]
+// CHECK: [[TYPE_NUM]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S<int>",
+S s1(42);
+S<int> s2(42);
diff --git a/test/CodeGenCXX/debug-info-use-after-free.cpp b/test/CodeGenCXX/debug-info-use-after-free.cpp
index f87763b9050d..100124889734 100644
--- a/test/CodeGenCXX/debug-info-use-after-free.cpp
+++ b/test/CodeGenCXX/debug-info-use-after-free.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple -emit-llvm-only %s
+// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple -emit-llvm-only -std=c++98 %s
+// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple -emit-llvm-only -std=c++11 %s
// Check that we don't crash.
// PR12305, PR12315
@@ -233,6 +235,7 @@ template < class > class scoped_ptr {
namespace {
class
AAA {
+protected:
virtual ~
AAA () {
}};
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index b082908b2c94..180e82de9fff 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -309,7 +309,7 @@ namespace test5 {
// CHECK5v03-NEXT: [[EXN:%.*]] = alloca i8*
// CHECK5v03-NEXT: [[SEL:%.*]] = alloca i32
// CHECK5-NEXT: [[PELEMS:%.*]] = bitcast [5 x [[A]]]* [[ELEMS]] to i8*
- // CHECK5-NEXT: call void @llvm.lifetime.start(i64 5, i8* [[PELEMS]])
+ // CHECK5-NEXT: call void @llvm.lifetime.start.p0i8(i64 5, i8* [[PELEMS]])
// CHECK5-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]], [5 x [[A]]]* [[ELEMS]], i32 0, i32 0
// CHECK5-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], [[A]]* [[BEGIN]], i64 5
// CHECK5-NEXT: br label
@@ -484,29 +484,29 @@ namespace test11 {
// CHECK6: {{^}}invoke.cont
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T1]])
// CHECK6: [[BC1:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T1]] to i8*
-// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC1]])
+// CHECK6: call void @llvm.lifetime.end.p0i8(i64 32, i8* [[BC1]])
// CHECK6: {{^}}lpad
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T1]])
// CHECK6: [[BC2:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T1]] to i8*
-// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC2]])
+// CHECK6: call void @llvm.lifetime.end.p0i8(i64 32, i8* [[BC2]])
// CHECK6: {{^}}invoke.cont
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T2]])
// CHECK6: [[BC3:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T2]] to i8*
-// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC3]])
+// CHECK6: call void @llvm.lifetime.end.p0i8(i64 32, i8* [[BC3]])
// CHECK6: {{^}}lpad
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T2]])
// CHECK6: [[BC4:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T2]] to i8*
-// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC4]])
+// CHECK6: call void @llvm.lifetime.end.p0i8(i64 32, i8* [[BC4]])
// CHECK6: {{^}}invoke.cont
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T3]])
// CHECK6: [[BC5:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T3]] to i8*
-// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC5]])
+// CHECK6: call void @llvm.lifetime.end.p0i8(i64 32, i8* [[BC5]])
// CHECK6: {{^}}lpad
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T3]])
// CHECK6: [[BC6:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T3]] to i8*
-// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC6]])
+// CHECK6: call void @llvm.lifetime.end.p0i8(i64 32, i8* [[BC6]])
struct S1 {
~S1();
diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp
index 33e524cc9b01..bdef2eb06e69 100644
--- a/test/CodeGenCXX/dllexport.cpp
+++ b/test/CodeGenCXX/dllexport.cpp
@@ -108,8 +108,8 @@ inline int __declspec(dllexport) inlineStaticLocalsFunc() {
template<typename T> __declspec(dllexport) int VarTmplDef;
INSTVAR(VarTmplDef<ExplicitInst_Exported>)
-// MSC-DAG: @"\01??$VarTmplImplicitDef@UImplicitInst_Exported@@@@3HA" = external dllexport global
-// GNU-DAG: @_Z18VarTmplImplicitDefI21ImplicitInst_ExportedE = external dllexport global
+// MSC-DAG: @"\01??$VarTmplImplicitDef@UImplicitInst_Exported@@@@3HA" = external global
+// GNU-DAG: @_Z18VarTmplImplicitDefI21ImplicitInst_ExportedE = external global
template<typename T> __declspec(dllexport) int VarTmplImplicitDef;
USEVAR(VarTmplImplicitDef<ImplicitInst_Exported>)
@@ -528,7 +528,7 @@ struct __declspec(dllexport) T {
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a@T@@QAEXXZ"
static int b;
- // M32-DAG: @"\01?b@T@@2HA" = external dllexport global i32
+ // M32-DAG: @"\01?b@T@@2HA" = external global i32
static int c;
// M32-DAG: @"\01?c@T@@2HA" = dllexport global i32 0, align 4
diff --git a/test/CodeGenCXX/dllimport.cpp b/test/CodeGenCXX/dllimport.cpp
index 4ec14b72109f..372a96ba2efe 100644
--- a/test/CodeGenCXX/dllimport.cpp
+++ b/test/CodeGenCXX/dllimport.cpp
@@ -26,6 +26,7 @@ struct ExplicitSpec_NotImported {};
#define USEVARTYPE(type, var) type UNIQ(use)() { return var; }
#define USEVAR(var) USEVARTYPE(int, var)
#define USE(func) void UNIQ(use)() { func(); }
+#define USE1(func) void UNIQ(use)() { func(nullptr); }
#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; }
#define USESTATICMEMFUNC(class, func) void (*UNIQ(use)())() { return &class::func; }
#define USECLASS(class) void UNIQ(USE)() { class x; }
@@ -316,10 +317,13 @@ namespace ns { __declspec(dllimport) void externalFunc(); }
USE(ns::externalFunc)
// A dllimport function referencing non-imported vars or functions must not be available_externally.
+
__declspec(dllimport) int ImportedVar;
int NonImportedVar;
__declspec(dllimport) int ImportedFunc();
int NonImportedFunc();
+struct ClassWithNonImportedMethod { int f(); };
+
__declspec(dllimport) inline int ReferencingImportedVar() { return ImportedVar; }
// MO1-DAG: define available_externally dllimport i32 @"\01?ReferencingImportedVar@@YAHXZ"
__declspec(dllimport) inline int ReferencingNonImportedVar() { return NonImportedVar; }
@@ -328,10 +332,16 @@ __declspec(dllimport) inline int ReferencingImportedFunc() { return ImportedFunc
// MO1-DAG: define available_externally dllimport i32 @"\01?ReferencingImportedFunc@@YAHXZ"
__declspec(dllimport) inline int ReferencingNonImportedFunc() { return NonImportedFunc(); }
// MO1-DAG: declare dllimport i32 @"\01?ReferencingNonImportedFunc@@YAHXZ"()
+__declspec(dllimport) inline int ReferencingNonImportedMethod(ClassWithNonImportedMethod *x) { return x->f(); }
+// MO1-DAG: declare dllimport i32 @"\01?ReferencingNonImportedMethod
+__declspec(dllimport) inline int ReferencingClassMemberPtr(int (ClassWithNonImportedMethod::*p)(), ClassWithNonImportedMethod *x) { return (x->*p)(); }
+// MO1-DAG: define available_externally dllimport i32 @"\01?ReferencingClassMemberPtr@@YAHP8ClassWithNonImportedMethod@@AEHXZPAU1@@Z"
USE(ReferencingImportedVar)
USE(ReferencingNonImportedVar)
USE(ReferencingImportedFunc)
USE(ReferencingNonImportedFunc)
+USE1(ReferencingNonImportedMethod)
+void UNIQ(use)() { ReferencingClassMemberPtr(&ClassWithNonImportedMethod::f, nullptr); }
// References to operator new and delete count too, despite not being DeclRefExprs.
__declspec(dllimport) inline int *ReferencingNonImportedNew() { return new int[2]; }
// MO1-DAG: declare dllimport i32* @"\01?ReferencingNonImportedNew@@YAPAHXZ"
@@ -348,7 +358,7 @@ __declspec(dllimport) inline int *ReferencingImportedDelete() { delete (int*)nul
USE(ReferencingImportedNew)
USE(ReferencingImportedDelete)
struct ClassWithDtor { ~ClassWithDtor() {} };
-struct __declspec(dllimport) ClassWithNonDllImportField { ClassWithDtor t; };
+struct __declspec(dllimport) ClassWithNonDllImportField { using X = ClassWithDtor; X t[2]; };
struct __declspec(dllimport) ClassWithNonDllImportBase : public ClassWithDtor { };
USECLASS(ClassWithNonDllImportField);
USECLASS(ClassWithNonDllImportBase);
@@ -358,6 +368,13 @@ struct ClassWithCtor { ClassWithCtor() {} };
struct __declspec(dllimport) ClassWithNonDllImportFieldWithCtor { ClassWithCtor t; };
USECLASS(ClassWithNonDllImportFieldWithCtor);
// MO1-DAG: declare dllimport x86_thiscallcc %struct.ClassWithNonDllImportFieldWithCtor* @"\01??0ClassWithNonDllImportFieldWithCtor@@QAE@XZ"(%struct.ClassWithNonDllImportFieldWithCtor* returned)
+struct ClassWithImplicitDtor { __declspec(dllimport) ClassWithImplicitDtor(); ClassWithDtor member; };
+__declspec(dllimport) inline void ReferencingDtorThroughDefinition() { ClassWithImplicitDtor x; };
+USE(ReferencingDtorThroughDefinition)
+// MO1-DAG: declare dllimport void @"\01?ReferencingDtorThroughDefinition@@YAXXZ"()
+__declspec(dllimport) inline void ReferencingDtorThroughTemporary() { ClassWithImplicitDtor(); };
+USE(ReferencingDtorThroughTemporary)
+// MO1-DAG: declare dllimport void @"\01?ReferencingDtorThroughTemporary@@YAXXZ"()
// A dllimport function with a TLS variable must not be available_externally.
__declspec(dllimport) inline void FunctionWithTLSVar() { static __thread int x = 42; }
@@ -395,17 +412,17 @@ USE(inlineFuncTmpl1<ImplicitInst_Imported>)
template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {}
USE(inlineFuncTmpl2<ImplicitInst_Imported>)
-// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"()
+// MSC-DAG: define linkonce_odr void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"()
// GNU-DAG: define linkonce_odr void @_Z18inlineFuncTmplDeclI21ImplicitInst_ImportedEvv()
-// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"()
+// MO1-DAG: define linkonce_odr void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"()
// GO1-DAG: define linkonce_odr void @_Z18inlineFuncTmplDeclI21ImplicitInst_ImportedEvv()
template<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl();
template<typename T> void inlineFuncTmplDecl() {}
USE(inlineFuncTmplDecl<ImplicitInst_Imported>)
-// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"()
+// MSC-DAG: define linkonce_odr void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"()
// GNU-DAG: define linkonce_odr void @_Z17inlineFuncTmplDefI21ImplicitInst_ImportedEvv()
-// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"()
+// MO1-DAG: define linkonce_odr void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"()
// GO1-DAG: define linkonce_odr void @_Z17inlineFuncTmplDefI21ImplicitInst_ImportedEvv()
template<typename T> __declspec(dllimport) void inlineFuncTmplDef();
template<typename T> inline void inlineFuncTmplDef() {}
@@ -439,7 +456,7 @@ USE(funcTmplRedecl3<ImplicitInst_NotImported>)
// GNU-DAG: declare void @_Z15funcTmplFriend2I24ImplicitInst_NotImportedEvv()
// MSC-DAG: define linkonce_odr void @"\01??$funcTmplFriend3@UImplicitInst_NotImported@@@@YAXXZ"()
// GNU-DAG: define linkonce_odr void @_Z15funcTmplFriend3I24ImplicitInst_NotImportedEvv()
-// MSC-DAG: declare dllimport void @"\01??$funcTmplFriend4@UImplicitInst_Imported@@@@YAXXZ"()
+// MSC-DAG: define linkonce_odr void @"\01??$funcTmplFriend4@UImplicitInst_Imported@@@@YAXXZ"()
// GNU-DAG: define linkonce_odr void @_Z15funcTmplFriend4I21ImplicitInst_ImportedEvv()
struct FuncTmplFriend {
template<typename T> friend __declspec(dllimport) void funcTmplFriend1();
diff --git a/test/CodeGenCXX/dynamic-cast-hint.cpp b/test/CodeGenCXX/dynamic-cast-hint.cpp
index 27b76e07ffee..f88d39d3113c 100644
--- a/test/CodeGenCXX/dynamic-cast-hint.cpp
+++ b/test/CodeGenCXX/dynamic-cast-hint.cpp
@@ -1,7 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -emit-llvm -std=c++98 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -emit-llvm -std=c++11 -o - %s | FileCheck %s
-class A { virtual ~A() {} };
-class B { virtual ~B() {} };
+class A { protected: virtual ~A() {} };
+class B { protected: virtual ~B() {} };
class C : A { char x; };
class D : public A { short y; };
diff --git a/test/CodeGenCXX/exceptions-cxx-new.cpp b/test/CodeGenCXX/exceptions-cxx-new.cpp
index 3329aea32ef2..9836da8e540b 100644
--- a/test/CodeGenCXX/exceptions-cxx-new.cpp
+++ b/test/CodeGenCXX/exceptions-cxx-new.cpp
@@ -55,12 +55,12 @@ void test_cleanup() {
// CHECK: to label %[[LEAVE_FUNC:.*]] unwind label %[[CLEANUP:.*]]
// CHECK: [[LEAVE_FUNC]]
-// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAE@XZ"(
+// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"(
// CHECK: ret void
// CHECK: [[CLEANUP]]
// CHECK: %[[CLEANUPPAD:.*]] = cleanuppad within none []
-// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAE@XZ"(
+// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"(
// CHECK: cleanupret from %[[CLEANUPPAD]] unwind to caller
diff --git a/test/CodeGenCXX/exceptions-seh.cpp b/test/CodeGenCXX/exceptions-seh.cpp
index 7a11a1e50582..4f7eacd66720 100644
--- a/test/CodeGenCXX/exceptions-seh.cpp
+++ b/test/CodeGenCXX/exceptions-seh.cpp
@@ -118,7 +118,7 @@ void use_inline() {
use_seh_in_inline_func();
}
-// CHECK-LABEL: define linkonce_odr void @use_seh_in_inline_func() #{{[0-9]+}} comdat
+// CHECK-LABEL: define linkonce_odr void @use_seh_in_inline_func() #{{[0-9]+}}
// CHECK-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
// CHECK: invoke void @might_throw()
//
@@ -134,12 +134,12 @@ void use_inline() {
// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
// CHECK: call void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 1, i8* %[[fp]])
-// CHECK-LABEL: define internal i32 @"\01?filt$0@0@use_seh_in_inline_func@@"(i8* %exception_pointers, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func)
+// CHECK-LABEL: define internal i32 @"\01?filt$0@0@use_seh_in_inline_func@@"(i8* %exception_pointers, i8* %frame_pointer) #{{[0-9]+}}
// CHECK: icmp eq i32 %{{.*}}, 424242
// CHECK: zext i1 %{{.*}} to i32
// CHECK: ret i32
-// CHECK-LABEL: define internal void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 %abnormal_termination, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func)
+// CHECK-LABEL: define internal void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 %abnormal_termination, i8* %frame_pointer) #{{[0-9]+}}
// CHECK: store i32 1234, i32* @my_unique_global
// CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index fb5711878764..85857fb6fb8c 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -5,6 +5,9 @@
// This check logically is attached to 'template int S<int>::i;' below.
// CHECK: @_ZN1SIiE1iE = weak_odr global i32
+// This check is logically attached to 'template int ExportedStaticLocal::f<int>()' below.
+// CHECK-OPT: @_ZZN19ExportedStaticLocal1fIiEEvvE1i = linkonce_odr global
+
template<typename T, typename U, typename Result>
struct plus {
Result operator()(const T& t, const U& u) const;
@@ -153,3 +156,17 @@ template <typename T> void S<T>::f() {}
template <typename T> void S<T>::g() {}
template <typename T> int S<T>::i;
template <typename T> void S<T>::S2::h() {}
+
+namespace ExportedStaticLocal {
+void sink(int&);
+template <typename T>
+inline void f() {
+ static int i;
+ sink(i);
+}
+// See the check line at the top of the file.
+extern template void f<int>();
+void use() {
+ f<int>();
+}
+}
diff --git a/test/CodeGenCXX/float128-declarations.cpp b/test/CodeGenCXX/float128-declarations.cpp
index e1604a61cac7..f1db8f41c608 100644
--- a/test/CodeGenCXX/float128-declarations.cpp
+++ b/test/CodeGenCXX/float128-declarations.cpp
@@ -8,6 +8,10 @@
// RUN: %s -o - | FileCheck %s -check-prefix=CHECK-X86
// RUN: %clang_cc1 -emit-llvm -triple systemz-unknown-linux-gnu -std=c++11 \
// RUN: %s -o - | FileCheck %s -check-prefix=CHECK-SYSZ
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-openbsd -std=c++11 \
+// RUN: %s -o - | FileCheck %s -check-prefix=CHECK-X86
+// RUN: %clang_cc1 -emit-llvm -triple amd64-pc-openbsd -std=c++11 \
+// RUN: %s -o - | FileCheck %s -check-prefix=CHECK-X86
//
/* Various contexts where type __float128 can appear. The different check
prefixes are due to different mangling on X86 and different calling
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index 291b43cac0a0..f96e6032ff58 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -15,7 +15,7 @@ struct C { void *field; };
struct D { ~D(); };
-// CHECK: @__dso_handle = external global i8
+// CHECK: @__dso_handle = external hidden global i8
// CHECK: @c = global %struct.C zeroinitializer, align 8
// PR6205: The casts should not require global initializers
diff --git a/test/CodeGenCXX/implicit-exception-spec.cpp b/test/CodeGenCXX/implicit-exception-spec.cpp
new file mode 100644
index 000000000000..cf363bd685ad
--- /dev/null
+++ b/test/CodeGenCXX/implicit-exception-spec.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions | FileCheck -check-prefix=CHECK %s
+
+struct A {
+ A();
+ A(const A&);
+ A(A&&);
+};
+struct B : virtual A {
+ virtual void f() = 0;
+};
+struct C : B {
+ void f();
+};
+
+// CHECK-DAG: define {{.*}} @_ZN1BC2Ev({{.*}} #[[NOUNWIND:[0-9]*]]
+C c1;
+// CHECK-DAG: define {{.*}} @_ZN1BC2ERKS_({{.*}} #[[NOUNWIND]]
+C c2(c1);
+// CHECK-DAG: define {{.*}} @_ZN1BC2EOS_({{.*}} #[[NOUNWIND]]
+C c3(static_cast<C&&>(c1));
+
+// CHECK-DAG: #[[NOUNWIND]] = {{{.*}} nounwind
diff --git a/test/CodeGenCXX/inheriting-constructor.cpp b/test/CodeGenCXX/inheriting-constructor.cpp
index a3adf70ebb18..1be59b9305d3 100644
--- a/test/CodeGenCXX/inheriting-constructor.cpp
+++ b/test/CodeGenCXX/inheriting-constructor.cpp
@@ -137,7 +137,7 @@ namespace inalloca_nonvirt {
// WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]])
// WIN32: call void @llvm.stackrestore(
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
- // WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"(
+ // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
// On Win64, the Q arguments would be destroyed in the callee. We don't yet
// support that in the non-inlined case, so we force inlining.
@@ -150,7 +150,7 @@ namespace inalloca_nonvirt {
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]])
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
- // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]])
+ // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
struct C : B { using B::B; };
C c(1, 2, 3, 4);
@@ -173,7 +173,7 @@ namespace inalloca_nonvirt {
// WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]])
// WIN32: call void @llvm.stackrestore(
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
- // WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"(
+ // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
// On Win64, the Q arguments would be destroyed in the callee. We don't yet
// support that in the non-inlined case, so we force inlining.
@@ -186,7 +186,7 @@ namespace inalloca_nonvirt {
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]])
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
- // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]])
+ // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
}
namespace inalloca_virt {
@@ -224,7 +224,7 @@ namespace inalloca_virt {
// destroy the parameters, but that's not actually possible.
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
- // WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"(
+ // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
// On Win64, the Q arguments would be destroyed in the callee. We don't yet
// support that in the non-inlined case, so we force inlining.
@@ -239,7 +239,7 @@ namespace inalloca_virt {
// WIN64: br
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
- // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]])
+ // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
struct C : B { using B::B; };
C c(1, 2, 3, 4);
@@ -281,7 +281,7 @@ namespace inalloca_virt {
//
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
- // WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"(
+ // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
// On Win64, the Q arguments would be destroyed in the callee. We don't yet
// support that in the non-inlined case, so we force inlining.
@@ -301,7 +301,7 @@ namespace inalloca_virt {
// WIN64: br
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
- // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]])
+ // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
}
namespace inline_nonvirt {
diff --git a/test/CodeGenCXX/initializer-list-ctor-order.cpp b/test/CodeGenCXX/initializer-list-ctor-order.cpp
new file mode 100644
index 000000000000..390fe4f5c304
--- /dev/null
+++ b/test/CodeGenCXX/initializer-list-ctor-order.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - -triple i686-linux-gnu | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ITANIUM
+// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - -triple i686-windows | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MS
+
+extern "C" {
+int f();
+int g();
+}
+
+struct A {
+ A(int, int);
+};
+
+
+void foo() {
+ A a{f(), g()};
+}
+// CHECK-ITANIUM-LABEL: define void @_Z3foov
+// CHECK-MS-LABEL: define void @"\01?foo@@YAXXZ"
+// CHECK: call i32 @f()
+// CHECK: call i32 @g()
+
+struct B : A {
+ B();
+};
+B::B() : A{f(), g()} {}
+// CHECK-ITANIUM-LABEL: define void @_ZN1BC2Ev
+// CHECK-MS-LABEL: define x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ"
+// CHECK: call i32 @f()
+// CHECK: call i32 @g()
diff --git a/test/CodeGenCXX/linetable-cleanup.cpp b/test/CodeGenCXX/linetable-cleanup.cpp
index fbef05e53267..748f056918b9 100644
--- a/test/CodeGenCXX/linetable-cleanup.cpp
+++ b/test/CodeGenCXX/linetable-cleanup.cpp
@@ -1,10 +1,12 @@
// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -triple x86_64-apple-darwin10 -std=c++98 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -triple x86_64-apple-darwin10 -std=c++11 %s -o - | FileCheck %s
// Check the line numbers for cleanup code with EH in combination with
// simple return expressions.
// CHECK: define {{.*}}foo
-// CHECK: call void @_ZN1CD1Ev(%class.C* {{.*}}), !dbg ![[RET:[0-9]+]]
+// CHECK: call void @_ZN1CD1Ev(%class.C* {{.*}}){{( #[0-9])?}}, !dbg ![[RET:[0-9]+]]
// CHECK: ret i32 0, !dbg ![[RET]]
// CHECK: define {{.*}}bar
diff --git a/test/CodeGenCXX/lpad-linetable.cpp b/test/CodeGenCXX/lpad-linetable.cpp
index 69236693c9c2..9b429bc2a223 100644
--- a/test/CodeGenCXX/lpad-linetable.cpp
+++ b/test/CodeGenCXX/lpad-linetable.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm -debug-info-kind=limited -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm -debug-info-kind=limited -triple x86_64-apple-darwin10 -std=c++98 %s -o - | FileCheck %s
// The landing pad should have the line number of the closing brace of the function.
// rdar://problem/13888152
// CHECK: ret i32
diff --git a/test/CodeGenCXX/mangle-unnamed.cpp b/test/CodeGenCXX/mangle-unnamed.cpp
index 43b7bd79537d..c90f47b26e70 100644
--- a/test/CodeGenCXX/mangle-unnamed.cpp
+++ b/test/CodeGenCXX/mangle-unnamed.cpp
@@ -48,6 +48,7 @@ int f5() {
return a;
}
+#if __cplusplus <= 199711L
int f6() {
static union {
union {
@@ -56,9 +57,10 @@ int f6() {
int b;
};
- // CHECK: _ZZ2f6vE1b
+ // CXX98: _ZZ2f6vE1b
return b;
}
+#endif
int f7() {
static union {
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 3a94071294d3..91fe6aeef298 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -1125,3 +1125,15 @@ namespace test57 {
// CHECK-LABEL: @_ZN6test571fILi0EEEvDTplcldtL_ZNS_1xEE1fIXLi0EEEET_E
template void f<0>(int);
}
+
+namespace test58 {
+ struct State {
+ bool m_fn1();
+ } a;
+ template <class T> struct identity { typedef T type; };
+ struct A {
+ template <typename T> A(T, bool (identity<T>::type::*)());
+ };
+ // CHECK-LABEL: @_ZN6test581AC1INS_5StateEEET_MNS_8identityIS3_E4typeEFbvE
+ void fn1() { A(a, &State::m_fn1); }
+}
diff --git a/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp b/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
index f03cd6c5632b..f3e43079c3eb 100644
--- a/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
+++ b/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
@@ -138,6 +138,6 @@ S3 *f(S2 &s) {
// CHECK: [[CALL:%.*]] = invoke i8* @__RTDynamicCast
// CHECK: [[BC:%.*]] = bitcast i8* [[CALL]] to %"struct.PR25606::S3"*
-// CHECK: call x86_thiscallcc void @"\01??_DCleanup@PR25606@@QAE@XZ"(
+// CHECK: call x86_thiscallcc void @"\01??_DCleanup@PR25606@@QAEXXZ"(
// CHECK: ret %"struct.PR25606::S3"* [[BC]]
}
diff --git a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
index 79ac1e12173b..96b4fa3478a2 100644
--- a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
+++ b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
@@ -259,14 +259,14 @@ void f() {
// WIN32-LIFETIME-LABEL: define void @"\01?f@lifetime_marker@@YAXXZ"()
// WIN32-LIFETIME: %[[c:.*]] = alloca %"struct.lifetime_marker::C"
// WIN32-LIFETIME: %[[bc0:.*]] = bitcast %"struct.lifetime_marker::C"* %c to i8*
-// WIN32-LIFETIME: call void @llvm.lifetime.start(i64 1, i8* %[[bc0]])
+// WIN32-LIFETIME: call void @llvm.lifetime.start.p0i8(i64 1, i8* %[[bc0]])
// WIN32-LIFETIME: invoke void @"\01?g@lifetime_marker@@YAXXZ"()
// WIN32-LIFETIME-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad0:[^ ]*]]
//
// WIN32-LIFETIME: [[cont]]
// WIN32-LIFETIME: call x86_thiscallcc void @"\01??1C@lifetime_marker@@QAE@XZ"({{.*}})
// WIN32-LIFETIME: %[[bc1:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8*
-// WIN32-LIFETIME: call void @llvm.lifetime.end(i64 1, i8* %[[bc1]])
+// WIN32-LIFETIME: call void @llvm.lifetime.end.p0i8(i64 1, i8* %[[bc1]])
//
// WIN32-LIFETIME: [[lpad0]]
// WIN32-LIFETIME-NEXT: cleanuppad
@@ -276,7 +276,7 @@ void f() {
// WIN32-LIFETIME: [[lpad1]]
// WIN32-LIFETIME-NEXT: cleanuppad
// WIN32-LIFETIME: %[[bc2:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8*
-// WIN32-LIFETIME: call void @llvm.lifetime.end(i64 1, i8* %[[bc2]])
+// WIN32-LIFETIME: call void @llvm.lifetime.end.p0i8(i64 1, i8* %[[bc2]])
}
struct class_2 {
diff --git a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
index 7eea41c8712e..eaae3493ccdc 100644
--- a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
+++ b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
@@ -64,6 +64,10 @@ struct BigWithDtor {
int a, b, c, d, e, f;
};
+struct BaseNoByval : Small {
+ int bb;
+};
+
// WIN32: declare void @"{{.*take_bools_and_chars.*}}"
// WIN32: (<{ i8, [3 x i8], i8, [3 x i8], %struct.SmallWithDtor,
// WIN32: i8, [3 x i8], i8, [3 x i8], i32, i8, [3 x i8] }>* inalloca)
@@ -127,6 +131,12 @@ void medium_arg(Medium s) {}
// WIN64: define void @"\01?medium_arg@@YAXUMedium@@@Z"(i64 %s.coerce)
// WOA: define arm_aapcs_vfpcc void @"\01?medium_arg@@YAXUMedium@@@Z"([2 x i32] %s.coerce)
+void base_no_byval_arg(BaseNoByval s) {}
+// LINUX-LABEL: define void @_Z17base_no_byval_arg11BaseNoByval(%struct.BaseNoByval* byval align 4 %s)
+// WIN32: define void @"\01?base_no_byval_arg@@YAXUBaseNoByval@@@Z"(i32 %s.0, i32 %s.1)
+// WIN64: define void @"\01?base_no_byval_arg@@YAXUBaseNoByval@@@Z"(i64 %s.coerce)
+// WOA: define arm_aapcs_vfpcc void @"\01?base_no_byval_arg@@YAXUBaseNoByval@@@Z"([2 x i32] %s.coerce)
+
void small_arg_with_ctor(SmallWithCtor s) {}
// LINUX-LABEL: define void @_Z19small_arg_with_ctor13SmallWithCtor(%struct.SmallWithCtor* byval align 4 %s)
// WIN32: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(i32 %s.0)
diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp
index 6397eeb7313f..4de6c3346611 100644
--- a/test/CodeGenCXX/microsoft-abi-structors.cpp
+++ b/test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -207,7 +207,7 @@ F::~F() {
void foo() {
F f;
}
-// DTORS3-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DF@test2@@UAE@XZ"({{.*}} {{.*}} comdat
+// DTORS3-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DF@test2@@QAEXXZ"({{.*}} {{.*}} comdat
// Do an adjustment from C* to F*.
// DTORS3: getelementptr i8, i8* %{{.*}}, i32 20
// DTORS3: bitcast i8* %{{.*}} to %"struct.test2::F"*
@@ -361,12 +361,12 @@ struct D : B, C { ~D(); };
void call_vbase_complete(D *d) {
d->~D();
// CHECK: define void @"\01?call_vbase_complete@dtors@@YAXPAUD@1@@Z"
-// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}})
+// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"struct.dtors::D"* %{{[^,]+}})
// CHECK: ret
}
// The complete dtor should call the base dtors for D and the vbase A (once).
-// CHECK: define linkonce_odr x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"({{.*}}) {{.*}} comdat
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"({{.*}}) {{.*}} comdat
// CHECK-NOT: call
// CHECK: call x86_thiscallcc void @"\01??1D@dtors@@QAE@XZ"
// CHECK-NOT: call
@@ -377,7 +377,7 @@ void call_vbase_complete(D *d) {
void destroy_d_complete() {
D d;
// CHECK: define void @"\01?destroy_d_complete@dtors@@YAXXZ"
-// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}})
+// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"struct.dtors::D"* %{{[^,]+}})
// CHECK: ret
}
@@ -387,7 +387,7 @@ void destroy_d_complete() {
void call_nv_deleting_dtor(D *d) {
delete d;
// CHECK: define void @"\01?call_nv_deleting_dtor@dtors@@YAXPAUD@1@@Z"
-// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}})
+// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"struct.dtors::D"* %{{[^,]+}})
// CHECK: call void @"\01??3@YAXPAX@Z"
// CHECK: ret
}
diff --git a/test/CodeGenCXX/microsoft-abi-throw.cpp b/test/CodeGenCXX/microsoft-abi-throw.cpp
index 7c2e2a8f901e..51076f841611 100644
--- a/test/CodeGenCXX/microsoft-abi-throw.cpp
+++ b/test/CodeGenCXX/microsoft-abi-throw.cpp
@@ -12,7 +12,7 @@
// CHECK-DAG: @"\01??_R0?AUV@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUV@@\00" }, comdat
// CHECK-DAG: @"_CT??_R0?AUV@@@81044" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUV@@@8" to i8*), i32 0, i32 4, i32 4, i32 1, i8* null }, section ".xdata", comdat
// CHECK-DAG: @"_CTA5?AUY@@" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.5 { i32 5, [5 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8", %eh.CatchableType* @"_CT??_R0?AUZ@@@81", %eh.CatchableType* @"_CT??_R0?AUW@@@8??0W@@QAE@ABU0@@Z44", %eh.CatchableType* @"_CT??_R0?AUM@@@818", %eh.CatchableType* @"_CT??_R0?AUV@@@81044"] }, section ".xdata", comdat
-// CHECK-DAG: @"_TI5?AUY@@" = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* bitcast (void (%struct.Y*)* @"\01??_DY@@QAE@XZ" to i8*), i8* null, i8* bitcast (%eh.CatchableTypeArray.5* @"_CTA5?AUY@@" to i8*) }, section ".xdata", comdat
+// CHECK-DAG: @"_TI5?AUY@@" = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* bitcast (void (%struct.Y*)* @"\01??_DY@@QAEXXZ" to i8*), i8* null, i8* bitcast (%eh.CatchableTypeArray.5* @"_CTA5?AUY@@" to i8*) }, section ".xdata", comdat
// CHECK-DAG: @"_CT??_R0?AUDefault@@@8??_ODefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor13* @"\01??_R0?AUDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Default*, %struct.Default*)* @"\01??_ODefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
// CHECK-DAG: @"_CT??_R0?AUVariadic@@@8??_OVariadic@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor14* @"\01??_R0?AUVariadic@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Variadic*, %struct.Variadic*)* @"\01??_OVariadic@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
// CHECK-DAG: @"_CT??_R0?AUTemplateWithDefault@@@8??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor25* @"\01??_R0?AUTemplateWithDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.TemplateWithDefault*, %struct.TemplateWithDefault*)* @"\01??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
index 416aefa6b715..20ecaf431650 100644
--- a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
@@ -84,7 +84,7 @@ B::~B() {
// CHECK: ret
- // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B*
+ // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DB@@QAEXXZ"(%struct.B*
// CHECK2: %[[THIS:.*]] = load %struct.B*, %struct.B** {{.*}}
// CHECK2: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
// CHECK2: %[[B_i8:.*]] = getelementptr i8, i8* %[[THIS_i8]], i32 8
@@ -102,7 +102,7 @@ B::~B() {
// CHECK2: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B*
// CHECK2: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR:.*]], align 4
// CHECK2: %[[THIS:.*]] = load %struct.B*, %struct.B** %[[THIS_ADDR]]
- // CHECK2: call x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* %[[THIS]])
+ // CHECK2: call x86_thiscallcc void @"\01??_DB@@QAEXXZ"(%struct.B* %[[THIS]])
// ...
// CHECK2: ret
}
@@ -208,7 +208,7 @@ void call_complete_dtor() {
B b;
// CHECK: call x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ"(%struct.B* %[[B:.*]], i32 1)
// CHECK-NOT: getelementptr
- // CHECK: call x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* %[[B]])
+ // CHECK: call x86_thiscallcc void @"\01??_DB@@QAEXXZ"(%struct.B* %[[B]])
// CHECK: ret
}
diff --git a/test/CodeGenCXX/modules-ts.cppm b/test/CodeGenCXX/modules-ts.cppm
index da3bcb2174a7..90f6b5319eb6 100644
--- a/test/CodeGenCXX/modules-ts.cppm
+++ b/test/CodeGenCXX/modules-ts.cppm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fmodules-ts -std=c++1z -triple=x86_64-linux-gnu -emit-module-interface %s -o %t.pcm
+// RUN: %clang_cc1 -fmodules-ts -std=c++1z -triple=x86_64-linux-gnu -fmodules-codegen -emit-module-interface %s -o %t.pcm
// RUN: %clang_cc1 -fmodules-ts -std=c++1z -triple=x86_64-linux-gnu %t.pcm -emit-llvm -o - | FileCheck %s
module FooBar;
@@ -8,6 +8,9 @@ export {
int f() { return 0; }
}
+// CHECK-LABEL: define weak_odr void @_Z2f2v(
+inline void f2() { }
+
// FIXME: Emit global variables and their initializers with this TU.
// Emit an initialization function that other TUs can call, with guard variable.
diff --git a/test/CodeGenCXX/new-array-init.cpp b/test/CodeGenCXX/new-array-init.cpp
index 0429ae770bc8..ccc218e2b2dc 100644
--- a/test/CodeGenCXX/new-array-init.cpp
+++ b/test/CodeGenCXX/new-array-init.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown %s -emit-llvm -fsanitize=signed-integer-overflow -o - | FileCheck --check-prefix=SIO %s
// CHECK: @[[ABC4:.*]] = {{.*}} constant [4 x i8] c"abc\00"
// CHECK: @[[ABC15:.*]] = {{.*}} constant [15 x i8] c"abc\00\00\00\00
@@ -116,3 +117,9 @@ void aggr_sufficient(int n) {
struct Aggr { int a, b; };
new Aggr[n] { 1, 2, 3 };
}
+
+// SIO-LABEL: define void @_Z14constexpr_testv
+void constexpr_test() {
+ // SIO: call i8* @_Zna{{.}}(i32 4)
+ new int[0+1]{0};
+}
diff --git a/test/CodeGenCXX/no-lto-unit.cpp b/test/CodeGenCXX/no-lto-unit.cpp
new file mode 100644
index 000000000000..24b8fd01546a
--- /dev/null
+++ b/test/CodeGenCXX/no-lto-unit.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -flto=thin -triple x86_64-unknown-linux -fvisibility hidden -emit-llvm-bc -o %t %s
+// RUN: llvm-dis -o - %t | FileCheck %s
+// RUN: %clang_cc1 -flto=thin -flto-unit -fno-lto-unit -triple x86_64-unknown-linux -fvisibility hidden -emit-llvm-bc -o %t %s
+// RUN: llvm-dis -o - %t | FileCheck %s
+
+// CHECK-NOT: !type
+class A {
+ virtual void f() {}
+};
+
+A *f() {
+ return new A;
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index d02206abae50..0f359b9c9000 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -182,11 +182,11 @@ X test6() {
return a;
// CHECK: [[A:%.*]] = alloca [[X:%.*]], align 8
// CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds %class.X, %class.X* [[A]], i32 0, i32 0
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* nonnull [[PTR]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[PTR]])
// CHECK-NEXT: call {{.*}} @_ZN1XC1Ev([[X]]* nonnull [[A]])
// CHECK-NEXT: call {{.*}} @_ZN1XC1ERKS_([[X]]* {{%.*}}, [[X]]* nonnull dereferenceable({{[0-9]+}}) [[A]])
// CHECK-NEXT: call {{.*}} @_ZN1XD1Ev([[X]]* nonnull [[A]])
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* nonnull [[PTR]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[PTR]])
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenCXX/optnone-class-members.cpp b/test/CodeGenCXX/optnone-class-members.cpp
index 70e3ee76e60a..b1d2f7b559d9 100644
--- a/test/CodeGenCXX/optnone-class-members.cpp
+++ b/test/CodeGenCXX/optnone-class-members.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 < %s -triple %itanium_abi_triple -fms-extensions -O2 -disable-llvm-optzns -emit-llvm -x c++ | FileCheck %s
+// RUN: %clang_cc1 < %s -triple %itanium_abi_triple -fms-extensions -O2 -disable-llvm-passes -emit-llvm -x c++ | FileCheck %s
// Test attribute 'optnone' on methods:
// -- member functions;
diff --git a/test/CodeGenCXX/optnone-def-decl.cpp b/test/CodeGenCXX/optnone-def-decl.cpp
index 4008bbe685f3..6e4e510b9bf6 100644
--- a/test/CodeGenCXX/optnone-def-decl.cpp
+++ b/test/CodeGenCXX/optnone-def-decl.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple %itanium_abi_triple -fms-extensions -O2 -disable-llvm-optzns -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple %itanium_abi_triple -fms-extensions -O2 -disable-llvm-passes -emit-llvm -o - | FileCheck %s
// Test optnone on both function declarations and function definitions.
// Verify also that we don't generate invalid IR functions with
diff --git a/test/CodeGenCXX/reference-init.cpp b/test/CodeGenCXX/reference-init.cpp
index 3a3eaeee78f6..ba7b282028cf 100644
--- a/test/CodeGenCXX/reference-init.cpp
+++ b/test/CodeGenCXX/reference-init.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -emit-llvm-only -triple %itanium_abi_triple -verify %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -verify %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - -std=c++98 | FileCheck %s --check-prefix=CHECK-CXX98
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - -std=c++11 | FileCheck %s --check-prefix=CHECK-CXX11
// expected-no-diagnostics
struct XPTParamDescriptor {};
@@ -23,3 +25,12 @@ Foo& ignoreSetMutex = *(new Foo);
// Binding to a bit-field that requires a temporary.
struct { int bitfield : 3; } s = { 3 };
const int &s2 = s.bitfield;
+
+// In C++98, this forms a reference to itself. In C++11 onwards, this performs
+// copy-construction.
+struct SelfReference { SelfReference &r; };
+extern SelfReference self_reference_1;
+SelfReference self_reference_2 = {self_reference_1};
+// CHECK-CXX98: @self_reference_2 = global %[[SELF_REF:.*]] { %[[SELF_REF]]* @self_reference_1 }
+// CHECK-CXX11: @self_reference_2 = global %[[SELF_REF:.*]] zeroinitializer
+// CHECK-CXX11: call {{.*}}memcpy{{.*}} @self_reference_2 {{.*}} @self_reference_1
diff --git a/test/CodeGenCXX/regcall.cpp b/test/CodeGenCXX/regcall.cpp
index 0cc6ad009324..0ff6fdf12a58 100644
--- a/test/CodeGenCXX/regcall.cpp
+++ b/test/CodeGenCXX/regcall.cpp
@@ -47,8 +47,8 @@ public:
// CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD2Ev
// CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD1Ev
// Windows ignores calling convention on constructor/destructors.
- // CHECK-WIN64-DAG: define linkonce_odr void @"\01??_Dtest_class@@QEAA@XZ"
- // CHECK-WIN32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_Dtest_class@@QAE@XZ"
+ // CHECK-WIN64-DAG: define linkonce_odr void @"\01??_Dtest_class@@QEAAXXZ"
+ // CHECK-WIN32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_Dtest_class@@QAEXXZ"
test_class& __regcall operator+=(const test_class&){
return *this;
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index bb974948a059..925ddec1ad06 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -triple=x86_64-pc-linuxs -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-linuxs -emit-llvm -std=c++98 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK98 %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-linuxs -emit-llvm -std=c++11 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s
// CHECK: @_ZZ1hvE1i = internal global i32 0, align 4
// CHECK: @base_req = global [4 x i8] c"foo\00", align 1
@@ -9,7 +10,8 @@
// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0, comdat, align 4
// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0, comdat, align 8{{$}}
// CHECK: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16
-// CHECK: @_ZZN5test414useStaticLocalEvE3obj = linkonce_odr global %"struct.test4::HasVTable" zeroinitializer, comdat, align 8
+// CHECK98: @_ZZN5test414useStaticLocalEvE3obj = linkonce_odr global %"struct.test4::HasVTable" zeroinitializer, comdat, align 8
+// CHECK11: @_ZZN5test414useStaticLocalEvE3obj = linkonce_odr global { i8** } { i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTVN5test49HasVTableE, i32 0, inrange i32 0, i32 2) }, comdat, align 8
struct A {
A();
@@ -169,5 +171,5 @@ void useit() {
useStaticLocal();
}
// CHECK: define linkonce_odr dereferenceable(8) %"struct.test4::HasVTable"* @_ZN5test414useStaticLocalEv()
-// CHECK: ret %"struct.test4::HasVTable"* @_ZZN5test414useStaticLocalEvE3obj
+// CHECK: ret %"struct.test4::HasVTable"*{{.*}} @_ZZN5test414useStaticLocalEvE3obj
}
diff --git a/test/CodeGenCXX/stmtexpr.cpp b/test/CodeGenCXX/stmtexpr.cpp
index 7bf19bbfb46d..5885a1663e63 100644
--- a/test/CodeGenCXX/stmtexpr.cpp
+++ b/test/CodeGenCXX/stmtexpr.cpp
@@ -80,3 +80,85 @@ int foo5(bool b) {
y = ({ A a(1); if (b) goto G; a.i; });
G: return y;
}
+
+// When we emit a full expression with cleanups that contains branches out of
+// the full expression, the result of the inner expression (the call to
+// call_with_cleanups in this case) may not dominate the fallthrough destination
+// of the shared cleanup block.
+//
+// In this case the CFG will be a sequence of two diamonds, but the only
+// dynamically possible execution paths are both left hand branches and both
+// right hand branches. The first diamond LHS will call bar, and the second
+// diamond LHS will assign the result to v, but the call to bar does not
+// dominate the assignment.
+int bar(A, int);
+extern "C" int cleanup_exit_scalar(bool b) {
+ int v = bar(A(1), ({ if (b) return 42; 13; }));
+ return v;
+}
+
+// CHECK-LABEL: define{{.*}} i32 @cleanup_exit_scalar({{.*}})
+// CHECK: call {{.*}} @_ZN1AC1Ei
+// Spill after bar.
+// CHECK: %[[v:[^ ]*]] = call{{.*}} i32 @_Z3bar1Ai({{.*}})
+// CHECK-NEXT: store i32 %[[v]], i32* %[[tmp:[^, ]*]]
+// Do cleanup.
+// CHECK: call {{.*}} @_ZN1AD1Ev
+// CHECK: switch
+// Reload before v assignment.
+// CHECK: %[[v:[^ ]*]] = load i32, i32* %[[tmp]]
+// CHECK-NEXT: store i32 %[[v]], i32* %v
+
+// No need to spill when the expression result is a constant, constants don't
+// have dominance problems.
+extern "C" int cleanup_exit_scalar_constant(bool b) {
+ int v = (A(1), (void)({ if (b) return 42; 0; }), 13);
+ return v;
+}
+
+// CHECK-LABEL: define{{.*}} i32 @cleanup_exit_scalar_constant({{.*}})
+// CHECK: store i32 13, i32* %v
+
+// Check for the same bug for lvalue expression evaluation kind.
+// FIXME: What about non-reference lvalues, like bitfield lvalues and vector
+// lvalues?
+int &getref();
+extern "C" int cleanup_exit_lvalue(bool cond) {
+ int &r = (A(1), ({ if (cond) return 0; (void)0; }), getref());
+ return r;
+}
+// CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue({{.*}})
+// CHECK: call {{.*}} @_ZN1AC1Ei
+// Spill after bar.
+// CHECK: %[[v:[^ ]*]] = call dereferenceable(4) i32* @_Z6getrefv({{.*}})
+// CHECK-NEXT: store i32* %[[v]], i32** %[[tmp:[^, ]*]]
+// Do cleanup.
+// CHECK: call {{.*}} @_ZN1AD1Ev
+// CHECK: switch
+// Reload before v assignment.
+// CHECK: %[[v:[^ ]*]] = load i32*, i32** %[[tmp]]
+// CHECK-NEXT: store i32* %[[v]], i32** %r
+
+
+// We handle ExprWithCleanups for complex evaluation type separately, and it had
+// the same bug.
+_Complex float bar_complex(A, int);
+extern "C" int cleanup_exit_complex(bool b) {
+ _Complex float v = bar_complex(A(1), ({ if (b) return 42; 13; }));
+ return v;
+}
+
+// CHECK-LABEL: define{{.*}} i32 @cleanup_exit_complex({{.*}})
+// CHECK: call {{.*}} @_ZN1AC1Ei
+// Spill after bar.
+// CHECK: call {{.*}} @_Z11bar_complex1Ai({{.*}})
+// CHECK: store float %{{.*}}, float* %[[tmp1:[^, ]*]]
+// CHECK: store float %{{.*}}, float* %[[tmp2:[^, ]*]]
+// Do cleanup.
+// CHECK: call {{.*}} @_ZN1AD1Ev
+// CHECK: switch
+// Reload before v assignment.
+// CHECK: %[[v1:[^ ]*]] = load float, float* %[[tmp1]]
+// CHECK: %[[v2:[^ ]*]] = load float, float* %[[tmp2]]
+// CHECK: store float %[[v1]], float* %v.realp
+// CHECK: store float %[[v2]], float* %v.imagp
diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp
index 3d0ce234371f..098f18dc479f 100644
--- a/test/CodeGenCXX/template-instantiation.cpp
+++ b/test/CodeGenCXX/template-instantiation.cpp
@@ -1,21 +1,22 @@
-// RUN: %clang_cc1 %s -O1 -disable-llvm-passes -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
-
-// CHECK: @_ZN7PR100011xE = global
-// CHECK-NOT: @_ZN7PR100014kBarE = external global i32
-//
-// CHECK-NOT: @_ZTVN5test118stdio_sync_filebufIwEE = constant
-// CHECK-NOT: _ZTVN5test315basic_fstreamXXIcEE
-// CHECK-NOT: @_ZTVN5test018stdio_sync_filebufIA1_iEE
-// CHECK-NOT: @_ZTVN5test018stdio_sync_filebufIA2_iEE
-// CHECK: @_ZTVN5test018stdio_sync_filebufIA3_iEE = weak_odr unnamed_addr constant
-
-// CHECK: @_ZN7PR100011SIiE3arrE = linkonce_odr global [3 x i32]
-// CHECK-NOT: @_ZN7PR100011SIiE3arr2E = linkonce_odr global [3 x i32]A
-
-// CHECK: @_ZTVN5test018stdio_sync_filebufIA4_iEE = linkonce_odr unnamed_addr constant
-
-// CHECK-NOT: _ZTVN5test31SIiEE
-// CHECK-NOT: _ZTSN5test31SIiEE
+// RUN: %clang_cc1 %s -O1 -disable-llvm-passes -triple=x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -O1 -disable-llvm-passes -triple=x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK2
+
+// Instantiation order varies on different C++ dialects (IE, between C++98 and C++11).
+// CHECK-DAG: @_ZN7PR100011xE = global
+// CHECK-DAG: @_ZTVN5test018stdio_sync_filebufIA3_iEE = weak_odr unnamed_addr constant
+// CHECK-DAG: @_ZN7PR100011SIiE3arrE = linkonce_odr global [3 x i32]
+// CHECK-DAG: @_ZTVN5test018stdio_sync_filebufIA4_iEE = linkonce_odr unnamed_addr constant
+
+// Negative checks go under prefix "CHECK2" to avoid interference with CHECK and CHECK-DAG.
+// CHECK2-NOT: @_ZN7PR100014kBarE = external global i32
+// CHECK2-NOT: @_ZTVN5test118stdio_sync_filebufIwEE = constant
+// CHECK2-NOT: _ZTVN5test315basic_fstreamXXIcEE
+// CHECK2-NOT: @_ZTVN5test018stdio_sync_filebufIA1_iEE
+// CHECK2-NOT: @_ZTVN5test018stdio_sync_filebufIA2_iEE
+// CHECK2-NOT: @_ZN7PR100011SIiE3arr2E = linkonce_odr global [3 x i32]A
+
+// CHECK2-NOT: _ZTVN5test31SIiEE
+// CHECK2-NOT: _ZTSN5test31SIiEE
// CHECK-LABEL: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* %this) unnamed_addr
// CHECK-LABEL: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_(
@@ -152,7 +153,7 @@ class B {
void f () {}
};
// Should not instantiate class B since it is introduced in namespace scope.
-// CHECK-NOT: _ZN6PR85051AILi0EE1B1fEv
+// CHECK2-NOT: _ZN6PR85051AILi0EE1B1fEv
template class A<0>;
}
diff --git a/test/CodeGenCXX/type-metadata-thinlto.cpp b/test/CodeGenCXX/type-metadata-thinlto.cpp
new file mode 100644
index 000000000000..2a586fc4c37c
--- /dev/null
+++ b/test/CodeGenCXX/type-metadata-thinlto.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -flto=thin -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -emit-llvm-bc -o %t %s
+// RUN: llvm-modextract -o - -n 1 %t | llvm-dis | FileCheck %s
+
+// CHECK: @_ZTV1A = linkonce_odr
+class A {
+ virtual void f() {}
+};
+
+A *f() {
+ return new A;
+}
diff --git a/test/CodeGenCXX/type-metadata.cpp b/test/CodeGenCXX/type-metadata.cpp
index 076b1fdf1808..6821e3624093 100644
--- a/test/CodeGenCXX/type-metadata.cpp
+++ b/test/CodeGenCXX/type-metadata.cpp
@@ -1,16 +1,16 @@
// Tests for the cfi-vcall feature:
-// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM --check-prefix=NDIAG %s
-// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
-// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
-// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=MS --check-prefix=TT-MS --check-prefix=NDIAG %s
+// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM --check-prefix=NDIAG %s
+// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
+// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
+// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=MS --check-prefix=TT-MS --check-prefix=NDIAG %s
// Tests for the whole-program-vtables feature:
-// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM %s
-// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS --check-prefix=TT-MS %s
+// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM %s
+// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS --check-prefix=TT-MS %s
// Tests for cfi + whole-program-vtables:
-// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=ITANIUM --check-prefix=TC-ITANIUM %s
-// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=MS --check-prefix=TC-MS %s
+// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=ITANIUM --check-prefix=TC-ITANIUM %s
+// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=MS --check-prefix=TC-MS %s
// ITANIUM: @_ZTV1A = {{[^!]*}}, !type [[A16:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL16:![0-9]+]]
diff --git a/test/CodeGenCXX/ubsan-bitfields.cpp b/test/CodeGenCXX/ubsan-bitfields.cpp
new file mode 100644
index 000000000000..5595db013db0
--- /dev/null
+++ b/test/CodeGenCXX/ubsan-bitfields.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=bool,enum | FileCheck %s
+
+enum E {
+ a = 1,
+ b = 2,
+ c = 3
+};
+
+struct S {
+ E e1 : 10;
+};
+
+// CHECK-LABEL: define i32 @_Z4loadP1S
+E load(S *s) {
+ // CHECK: [[LOAD:%.*]] = load i16, i16* {{.*}}
+ // CHECK: [[CLEAR:%.*]] = and i16 [[LOAD]], 1023
+ // CHECK: [[CAST:%.*]] = zext i16 [[CLEAR]] to i32
+ // CHECK: icmp ule i32 [[CAST]], 3, !nosanitize
+ // CHECK: call void @__ubsan_handle_load_invalid_value
+ return s->e1;
+}
+
+struct Bool {
+ bool b1 : 1;
+ bool b2 : 7;
+ bool b3 : 16;
+};
+
+// CHECK-LABEL: define zeroext i1 @_Z13load_cpp_boolP4Bool
+bool load_cpp_bool(Bool *b) {
+ // CHECK-NOT: call void @__ubsan_handle_load_invalid_value
+ // CHECK-NOT: !nosanitize
+ return b->b1 || b->b2 || b->b3;
+}
diff --git a/test/CodeGenCXX/ubsan-global-alignment.cpp b/test/CodeGenCXX/ubsan-global-alignment.cpp
new file mode 100644
index 000000000000..67fcfd469a96
--- /dev/null
+++ b/test/CodeGenCXX/ubsan-global-alignment.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=alignment | FileCheck %s
+
+struct S {
+ int I;
+};
+
+extern S g_S;
+extern S array_S[];
+
+// CHECK-LABEL: define i32 @_Z18load_extern_global
+int load_extern_global() {
+ // FIXME: The IR builder constant-folds the alignment check away to 'true'
+ // here, so we never call the diagnostic. This is PR32630.
+ // CHECK-NOT: ptrtoint i32* {{.*}} to i32, !nosanitize
+ // CHECK: [[I:%.*]] = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @g_S, i32 0, i32 0), align 4
+ // CHECK-NEXT: ret i32 [[I]]
+ return g_S.I;
+}
+
+// CHECK-LABEL: define i32 @_Z22load_from_extern_array
+int load_from_extern_array(int I) {
+ // CHECK: [[I:%.*]] = getelementptr inbounds %struct.S, %struct.S* {{.*}}, i32 0, i32 0
+ // CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint i32* [[I]] to i64, !nosanitize
+ // CHECK-NEXT: [[AND:%.*]] = and i64 [[PTRTOINT]], 3, !nosanitize
+ // CHECK-NEXT: [[ICMP:%.*]] = icmp eq i64 [[AND]], 0, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]]
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ return array_S[I].I;
+}
diff --git a/test/CodeGenCXX/ubsan-suppress-checks.cpp b/test/CodeGenCXX/ubsan-suppress-checks.cpp
new file mode 100644
index 000000000000..8ec94556c136
--- /dev/null
+++ b/test/CodeGenCXX/ubsan-suppress-checks.cpp
@@ -0,0 +1,221 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=alignment | FileCheck %s --check-prefixes=CHECK,ALIGN
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s --check-prefixes=CHECK,NULL
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=alignment,null -DCHECK_LAMBDA | FileCheck %s --check-prefixes=LAMBDA
+
+struct A {
+ int foo;
+
+ // CHECK-LABEL: define linkonce_odr void @_ZN1A10do_nothingEv
+ void do_nothing() {
+ // ALIGN: %[[THISINT1:[0-9]+]] = ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT1]], 3, !nosanitize
+ // NULL: icmp ne %struct.A* %[[THIS1:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.A* %[[THIS1]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ // CHECK: ret void
+ }
+
+#ifdef CHECK_LAMBDA
+ // LAMBDA-LABEL: define linkonce_odr void @_ZN1A22do_nothing_with_lambdaEv
+ void do_nothing_with_lambda() {
+ // LAMBDA: icmp ne %struct.A* %[[THIS2:[a-z0-9]+]], null, !nosanitize
+ // LAMBDA: %[[THISINT2:[0-9]+]] = ptrtoint %struct.A* %[[THIS2]] to i64, !nosanitize
+ // LAMBDA: and i64 %[[THISINT2]], 3, !nosanitize
+ // LAMBDA: call void @__ubsan_handle_type_mismatch
+
+ auto f = [&] {
+ foo = 0;
+ };
+ f();
+
+ // LAMBDA: icmp ne %class.anon* %[[FUNCVAR:.*]], null, !nosanitize
+ // LAMBDA: %[[LAMBDAINT:[0-9]+]] = ptrtoint %class.anon* %[[FUNCVAR]] to i64, !nosanitize
+ // LAMBDA: and i64 %[[LAMBDAINT]], 7, !nosanitize
+ // LAMBDA: call void @__ubsan_handle_type_mismatch
+
+ // LAMBDA-NOT: call void @__ubsan_handle_type_mismatch
+ // LAMBDA: ret void
+ }
+
+// Check the IR for the lambda:
+//
+// LAMBDA-LABEL: define linkonce_odr void @_ZZN1A22do_nothing_with_lambdaEvENKUlvE_clEv
+// LAMBDA: call void @__ubsan_handle_type_mismatch
+// LAMBDA-NOT: call void @__ubsan_handle_type_mismatch
+// LAMBDA: ret void
+#endif
+
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11load_memberEv
+ int load_member() {
+ // ALIGN: %[[THISINT3:[0-9]+]] = ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT3]], 3, !nosanitize
+ // NULL: icmp ne %struct.A* %[[THIS3:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.A* %[[THIS3]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ return foo;
+ // CHECK: ret i32
+ }
+
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11call_methodEv
+ int call_method() {
+ // ALIGN: %[[THISINT4:[0-9]+]] = ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT4]], 3, !nosanitize
+ // NULL: icmp ne %struct.A* %[[THIS4:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.A* %[[THIS4]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ return load_member();
+ // CHECK: ret i32
+ }
+
+ // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_1Ev
+ void assign_member_1() {
+ // ALIGN: %[[THISINT5:[0-9]+]] = ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT5]], 3, !nosanitize
+ // NULL: icmp ne %struct.A* %[[THIS5:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.A* %[[THIS5]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ foo = 0;
+ // CHECK: ret void
+ }
+
+ // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_2Ev
+ void assign_member_2() {
+ // ALIGN: %[[THISINT6:[0-9]+]] = ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT6]], 3, !nosanitize
+ // NULL: icmp ne %struct.A* %[[THIS6:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.A* %[[THIS6]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ (__extension__ (this))->foo = 0;
+ // CHECK: ret void
+ }
+
+ // CHECK-LABEL: define linkonce_odr void @_ZNK1A15assign_member_3Ev
+ void assign_member_3() const {
+ // ALIGN: %[[THISINT7:[0-9]+]] = ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT7]], 3, !nosanitize
+ // NULL: icmp ne %struct.A* %[[THIS7:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.A* %[[THIS7]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ const_cast<A *>(this)->foo = 0;
+ // CHECK: ret void
+ }
+
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN1A22call_through_referenceERS_
+ static int call_through_reference(A &a) {
+ // ALIGN: %[[OBJINT:[0-9]+]] = ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[OBJINT]], 3, !nosanitize
+ // ALIGN: call void @__ubsan_handle_type_mismatch
+ // NULL-NOT: call void @__ubsan_handle_type_mismatch
+ return a.load_member();
+ // CHECK: ret i32
+ }
+
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN1A20call_through_pointerEPS_
+ static int call_through_pointer(A *a) {
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ return a->load_member();
+ // CHECK: ret i32
+ }
+};
+
+struct B {
+ operator A*() const { return nullptr; }
+
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEv
+ static int load_member() {
+ // Check &b before converting it to an A*.
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ //
+ // Check the result of the conversion before using it.
+ // NULL: call void @__ubsan_handle_type_mismatch
+ //
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ B b;
+ return static_cast<A *>(b)->load_member();
+ // CHECK: ret i32
+ }
+};
+
+struct Base {
+ int foo;
+
+ virtual int load_member_1() = 0;
+};
+
+struct Derived : public Base {
+ int bar;
+
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_2Ev
+ int load_member_2() {
+ // ALIGN: %[[THISINT8:[0-9]+]] = ptrtoint %struct.Derived* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT8]], 7, !nosanitize
+ // ALIGN: call void @__ubsan_handle_type_mismatch
+ // NULL: icmp ne %struct.Derived* %[[THIS8:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.Derived* %[[THIS8]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ //
+ // Check the result of the cast before using it.
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ //
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ return dynamic_cast<Base *>(this)->load_member_1();
+ // CHECK: ret i32
+ }
+
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_3Ev
+ int load_member_3() {
+ // ALIGN: %[[THISINT9:[0-9]+]] = ptrtoint %struct.Derived* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT9]], 7, !nosanitize
+ // ALIGN: call void @__ubsan_handle_type_mismatch
+ // ALIGN: call void @__ubsan_handle_type_mismatch
+ // NULL: icmp ne %struct.Derived* %[[THIS9:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.Derived* %[[THIS9]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ return reinterpret_cast<Derived *>(static_cast<Base *>(this))->foo;
+ // CHECK: ret i32
+ }
+
+ // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_1Ev
+ int load_member_1() override {
+ // ALIGN: %[[THISINT10:[0-9]+]] = ptrtoint %struct.Derived* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %[[THISINT10]], 7, !nosanitize
+ // ALIGN: call void @__ubsan_handle_type_mismatch
+ // NULL: icmp ne %struct.Derived* %[[THIS10:[a-z0-9]+]], null, !nosanitize
+ // NULL: ptrtoint %struct.Derived* %[[THIS10]] to i64, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
+ return foo + bar;
+ // CHECK: ret i32
+ }
+};
+
+void force_irgen() {
+ A *a;
+ a->do_nothing();
+#ifdef CHECK_LAMBDA
+ a->do_nothing_with_lambda();
+#endif
+ a->load_member();
+ a->call_method();
+ a->assign_member_1();
+ a->assign_member_2();
+ a->assign_member_3();
+ A::call_through_reference(*a);
+ A::call_through_pointer(a);
+
+ B::load_member();
+
+ Base *b = new Derived;
+ b->load_member_1();
+
+ Derived *d;
+ d->load_member_2();
+ d->load_member_3();
+}
diff --git a/test/CodeGenCXX/ubsan-type-checks.cpp b/test/CodeGenCXX/ubsan-type-checks.cpp
new file mode 100644
index 000000000000..786d049dfb56
--- /dev/null
+++ b/test/CodeGenCXX/ubsan-type-checks.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=alignment | FileCheck %s -check-prefixes=ALIGN,COMMON
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s -check-prefixes=NULL,COMMON
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=object-size | FileCheck %s -check-prefixes=OBJSIZE,COMMON
+
+struct A {
+ // COMMON-LABEL: define linkonce_odr void @_ZN1A10do_nothingEv
+ void do_nothing() {
+ // ALIGN-NOT: ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
+
+ // NULL: icmp ne %struct.A* %{{.*}}, null, !nosanitize
+
+ // OBJSIZE-NOT: call i64 @llvm.objectsize
+ }
+};
+
+struct B {
+ int x;
+
+ // COMMON-LABEL: define linkonce_odr void @_ZN1B10do_nothingEv
+ void do_nothing() {
+ // ALIGN: ptrtoint %struct.B* %{{.*}} to i64, !nosanitize
+ // ALIGN: and i64 %{{.*}}, 3, !nosanitize
+
+ // NULL: icmp ne %struct.B* %{{.*}}, null, !nosanitize
+
+ // OBJSIZE-NOT: call i64 @llvm.objectsize
+ }
+};
+
+void force_irgen() {
+ A a;
+ a.do_nothing();
+
+ B b;
+ b.do_nothing();
+}
diff --git a/test/CodeGenCXX/unaligned.cpp b/test/CodeGenCXX/unaligned.cpp
new file mode 100644
index 000000000000..95549d3339f0
--- /dev/null
+++ b/test/CodeGenCXX/unaligned.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -x c++ -std=c++11 -triple x86_64-unknown-linux-gnu -fms-extensions -emit-llvm < %s | FileCheck %s
+
+int foo() {
+ // CHECK: ret i32 1
+ return alignof(__unaligned int);
+}
diff --git a/test/CodeGenCXX/volatile-1.cpp b/test/CodeGenCXX/volatile-1.cpp
index f32e4288b897..75fb0d26f413 100644
--- a/test/CodeGenCXX/volatile-1.cpp
+++ b/test/CodeGenCXX/volatile-1.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -Wno-unused-value -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -Wno-unused-value -triple %itanium_abi_triple -emit-llvm %s -std=c++98 -o - | FileCheck %s
+// RUN: %clang_cc1 -Wno-unused-value -triple %itanium_abi_triple -emit-llvm %s -std=c++11 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s
// CHECK: @i = global [[INT:i[0-9]+]] 0
volatile int i, j, k;
@@ -22,18 +23,22 @@ void test() {
asm("nop"); // CHECK: call void asm
- // should not load
+ // should not load in C++98
i;
+ // CHECK11-NEXT: load volatile [[INT]], [[INT]]* @i
(float)(ci);
// CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0)
// CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1)
// CHECK-NEXT: sitofp [[INT]]
- // These are not uses in C++:
+ // These are not uses in C++98:
// [expr.static.cast]p6:
// The lvalue-to-rvalue . . . conversions are not applied to the expression.
(void)ci;
+ // CHECK11-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0)
+ // CHECK11-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1)
+
(void)a;
(void)(ci=ci);
@@ -126,7 +131,8 @@ void test() {
// CHECK-NEXT: load volatile
// CHECK-NEXT: sitofp
- (void)i;
+ (void)i; // This is now a load in C++11
+ // CHECK11-NEXT: load volatile
i=i;
// CHECK-NEXT: load volatile
@@ -155,13 +161,15 @@ void test() {
// CHECK-NEXT: br label
// CHECK: phi
- (void)(i,(i=i));
+ (void)(i,(i=i)); // first i is also a load in C++11
+ // CHECK11-NEXT: load volatile
// CHECK-NEXT: load volatile
// CHECK-NEXT: store volatile
- i=i,k;
+ i=i,k; // k is also a load in C++11
// CHECK-NEXT: load volatile [[INT]], [[INT]]* @i
// CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i
+ // CHECK11-NEXT: load volatile [[INT]], [[INT]]* @k
(i=j,k=j);
// CHECK-NEXT: load volatile [[INT]], [[INT]]* @j
@@ -169,11 +177,14 @@ void test() {
// CHECK-NEXT: load volatile [[INT]], [[INT]]* @j
// CHECK-NEXT: store volatile {{.*}}, [[INT]]* @k
- (i=j,k);
+ (i=j,k); // k is also a load in C++11
// CHECK-NEXT: load volatile [[INT]], [[INT]]* @j
// CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i
+ // CHECK11-NEXT: load volatile [[INT]], [[INT]]* @k
- (i,j);
+ (i,j); // i and j both are loads in C++11
+ // CHECK11-NEXT: load volatile [[INT]], [[INT]]* @i
+ // CHECK11-NEXT: load volatile [[INT]], [[INT]]* @j
// Extra load in C++.
i=c=k;
@@ -190,7 +201,9 @@ void test() {
// CHECK-NEXT: add nsw [[INT]]
// CHECK-NEXT: store volatile
- ci;
+ ci; // ci is a load in C++11
+ // CHECK11-NEXT: load volatile {{.*}} @ci, i32 0, i32 0
+ // CHECK11-NEXT: load volatile {{.*}} @ci, i32 0, i32 1
asm("nop"); // CHECK-NEXT: call void asm
@@ -338,8 +351,9 @@ void test() {
// CHECK-NEXT: load volatile
// CHECK-NEXT: add
- (i,j)=k;
+ (i,j)=k; // i is also a load in C++11
// CHECK-NEXT: load volatile [[INT]], [[INT]]* @k
+ // CHECK11-NEXT: load volatile [[INT]], [[INT]]* @i
// CHECK-NEXT: store volatile {{.*}}, [[INT]]* @j
(j=k,i)=i;
diff --git a/test/CodeGenCXX/volatile.cpp b/test/CodeGenCXX/volatile.cpp
index ea7429f291c9..9c0271b21dfe 100644
--- a/test/CodeGenCXX/volatile.cpp
+++ b/test/CodeGenCXX/volatile.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -std=c++98 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s
// Check that IR gen doesn't try to do an lvalue-to-rvalue conversion
// on a volatile reference result. rdar://problem/8338198
@@ -27,6 +28,7 @@ namespace test1 {
// CHECK-LABEL: define void @_ZN5test14testEv()
void test() {
// CHECK: [[TMP:%.*]] = load i32*, i32** @_ZN5test11xE, align 8
+ // CHECK11-NEXT: {{%.*}} = load volatile i32, i32* [[TMP]], align 4
// CHECK-NEXT: ret void
*x;
}
diff --git a/test/CodeGenCoroutines/coro-alloc.cpp b/test/CodeGenCoroutines/coro-alloc.cpp
index 7dbbdd31be08..f0a600eabe9a 100644
--- a/test/CodeGenCoroutines/coro-alloc.cpp
+++ b/test/CodeGenCoroutines/coro-alloc.cpp
@@ -4,12 +4,27 @@ namespace std {
namespace experimental {
template <typename... T>
struct coroutine_traits; // expected-note {{declared here}}
+
+template <class Promise = void>
+struct coroutine_handle {
+ coroutine_handle() = default;
+ static coroutine_handle from_address(void *) { return {}; }
+};
+
+template <>
+struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) { return {}; }
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) {}
+};
+
}
}
struct suspend_always {
bool await_ready() { return false; }
- void await_suspend() {}
+ void await_suspend(std::experimental::coroutine_handle<>) {}
void await_resume() {}
};
@@ -25,7 +40,7 @@ struct std::experimental::coroutine_traits<void, global_new_delete_tag> {
};
};
-// CHECK-LABEL: f0(
+// CHECK-LABEL: f0(
extern "C" void f0(global_new_delete_tag) {
// CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
// CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
@@ -34,7 +49,7 @@ extern "C" void f0(global_new_delete_tag) {
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
// CHECK: call void @_ZdlPv(i8* %[[MEM]])
- co_await suspend_always{};
+ co_return;
}
struct promise_new_tag {};
@@ -50,7 +65,7 @@ struct std::experimental::coroutine_traits<void, promise_new_tag> {
};
};
-// CHECK-LABEL: f1(
+// CHECK-LABEL: f1(
extern "C" void f1(promise_new_tag ) {
// CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
// CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
@@ -59,7 +74,7 @@ extern "C" void f1(promise_new_tag ) {
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
// CHECK: call void @_ZdlPv(i8* %[[MEM]])
- co_await suspend_always{};
+ co_return;
}
struct promise_delete_tag {};
@@ -75,7 +90,7 @@ struct std::experimental::coroutine_traits<void, promise_delete_tag> {
};
};
-// CHECK-LABEL: f2(
+// CHECK-LABEL: f2(
extern "C" void f2(promise_delete_tag) {
// CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
// CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
@@ -84,7 +99,7 @@ extern "C" void f2(promise_delete_tag) {
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(i8* %[[MEM]])
- co_await suspend_always{};
+ co_return;
}
struct promise_sized_delete_tag {};
@@ -100,7 +115,7 @@ struct std::experimental::coroutine_traits<void, promise_sized_delete_tag> {
};
};
-// CHECK-LABEL: f3(
+// CHECK-LABEL: f3(
extern "C" void f3(promise_sized_delete_tag) {
// CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
// CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
@@ -110,5 +125,32 @@ extern "C" void f3(promise_sized_delete_tag) {
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
// CHECK: %[[SIZE2:.+]] = call i64 @llvm.coro.size.i64()
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv24promise_sized_delete_tagEE12promise_typedlEPvm(i8* %[[MEM]], i64 %[[SIZE2]])
- co_await suspend_always{};
+ co_return;
+}
+
+struct promise_on_alloc_failure_tag {};
+
+template<>
+struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> {
+ struct promise_type {
+ int get_return_object() {}
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() { return {}; }
+ void return_void() {}
+ static int get_return_object_on_allocation_failure() { return -1; }
+ };
+};
+
+// CHECK-LABEL: f4(
+extern "C" int f4(promise_on_alloc_failure_tag) {
+ // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
+ // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
+ // CHECK: %[[MEM:.+]] = call i8* @_Znwm(i64 %[[SIZE]])
+ // CHECK: %[[OK:.+]] = icmp ne i8* %[[MEM]], null
+ // CHECK: br i1 %[[OK]], label %[[OKBB:.+]], label %[[ERRBB:.+]]
+
+ // CHECK: [[ERRBB]]:
+ // CHECK: %[[RETVAL:.+]] = call i32 @_ZNSt12experimental16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv(
+ // CHECK: ret i32 %[[RETVAL]]
+ co_return;
}
diff --git a/test/CodeGenCoroutines/coro-await.cpp b/test/CodeGenCoroutines/coro-await.cpp
new file mode 100644
index 000000000000..b0fd0129de34
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-await.cpp
@@ -0,0 +1,230 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std {
+namespace experimental {
+template <typename... T>
+struct coroutine_traits;
+
+template <typename Promise = void> struct coroutine_handle;
+
+template <>
+struct coroutine_handle<void> {
+ void *ptr;
+ static coroutine_handle from_address(void *);
+};
+
+template <typename Promise>
+struct coroutine_handle : coroutine_handle<> {
+ static coroutine_handle from_address(void *);
+};
+
+}
+}
+
+struct suspend_always {
+ int stuff;
+ bool await_ready();
+ void await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+
+template<>
+struct std::experimental::coroutine_traits<void> {
+ struct promise_type {
+ void get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void return_void();
+ };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+
+ co_await suspend_always{};
+ // See if we need to suspend:
+ // --------------------------
+ // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* %[[AWAITABLE:.+]])
+ // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+ // If we are suspending:
+ // ---------------------
+ // CHECK: [[SUSPEND_BB]]:
+ // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+ // ---------------------------
+ // Build the coroutine handle and pass it to await_suspend
+ // ---------------------------
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+ // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+ // ... many lines of code to coerce coroutine_handle into an i8* scalar
+ // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+ // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* %[[AWAITABLE]], i8* %[[CH]])
+ // -------------------------
+ // Generate a suspend point:
+ // -------------------------
+ // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+ // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
+ // CHECK: i8 0, label %[[READY_BB]]
+ // CHECK: i8 1, label %[[CLEANUP_BB:.+]]
+ // CHECK: ]
+
+ // Cleanup code goes here:
+ // -----------------------
+ // CHECK: [[CLEANUP_BB]]:
+
+ // When coroutine is resumed, call await_resume
+ // --------------------------
+ // CHECK: [[READY_BB]]:
+ // CHECK: call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]])
+}
+
+struct suspend_maybe {
+ float stuff;
+ ~suspend_maybe();
+ bool await_ready();
+ bool await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+
+
+template<>
+struct std::experimental::coroutine_traits<void,int> {
+ struct promise_type {
+ void get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void return_void();
+ suspend_maybe yield_value(int);
+ };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(int) {
+ co_yield 42;
+ // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits<void, int>::promise_type"
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits<void, int>::promise_type"* %[[PROMISE]], i32 42)
+
+ // See if we need to suspend:
+ // --------------------------
+ // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(%struct.suspend_maybe* %[[AWAITABLE]])
+ // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+ // If we are suspending:
+ // ---------------------
+ // CHECK: [[SUSPEND_BB]]:
+ // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+ // ---------------------------
+ // Build the coroutine handle and pass it to await_suspend
+ // ---------------------------
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+ // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+ // ... many lines of code to coerce coroutine_handle into an i8* scalar
+ // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+ // CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_maybe* %[[AWAITABLE]], i8* %[[CH]])
+ // -------------------------------------------
+ // See if await_suspend decided not to suspend
+ // -------------------------------------------
+ // CHECK: br i1 %[[YES]], label %[[SUSPEND_PLEASE:.+]], label %[[READY_BB]]
+
+ // CHECK: [[SUSPEND_PLEASE]]:
+ // CHECK: call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+
+ // CHECK: [[READY_BB]]:
+ // CHECK: call void @_ZN13suspend_maybe12await_resumeEv(%struct.suspend_maybe* %[[AWAITABLE]])
+}
+
+struct ComplexAwaiter {
+ template <typename F> void await_suspend(F);
+ bool await_ready();
+ _Complex float await_resume();
+};
+extern "C" void UseComplex(_Complex float);
+
+// CHECK-LABEL: @TestComplex(
+extern "C" void TestComplex() {
+ UseComplex(co_await ComplexAwaiter{});
+ // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter*
+ // CHECK: call void @UseComplex(<2 x float> %{{.+}})
+
+ co_await ComplexAwaiter{};
+ // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter*
+
+ _Complex float Val = co_await ComplexAwaiter{};
+ // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter*
+}
+
+struct Aggr { int X, Y, Z; ~Aggr(); };
+struct AggrAwaiter {
+ template <typename F> void await_suspend(F);
+ bool await_ready();
+ Aggr await_resume();
+};
+
+extern "C" void Whatever();
+extern "C" void UseAggr(Aggr&&);
+
+// FIXME: Once the cleanup code is in, add testing that destructors for Aggr
+// are invoked properly on the cleanup branches.
+
+// CHECK-LABEL: @TestAggr(
+extern "C" void TestAggr() {
+ UseAggr(co_await AggrAwaiter{});
+ Whatever();
+ // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume:.+]],
+ // CHECK: call void @UseAggr(%struct.Aggr* dereferenceable(12) %[[AwaitResume]])
+ // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume]])
+ // CHECK: call void @Whatever()
+
+ co_await AggrAwaiter{};
+ Whatever();
+ // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume2:.+]],
+ // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume2]])
+ // CHECK: call void @Whatever()
+
+ Aggr Val = co_await AggrAwaiter{};
+ Whatever();
+ // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume3:.+]],
+ // CHECK: call void @Whatever()
+ // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume3]])
+}
+
+struct ScalarAwaiter {
+ template <typename F> void await_suspend(F);
+ bool await_ready();
+ int await_resume();
+};
+
+extern "C" void UseScalar(int);
+
+// CHECK-LABEL: @TestScalar(
+extern "C" void TestScalar() {
+ UseScalar(co_await ScalarAwaiter{});
+ // CHECK: %[[Result:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter*
+ // CHECK: call void @UseScalar(i32 %[[Result]])
+
+ int Val = co_await ScalarAwaiter{};
+ // CHECK: %[[Result2:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter*
+ // CHECK: store i32 %[[Result2]], i32* %Val
+
+ co_await ScalarAwaiter{};
+ // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter*
+}
+
+// Test operator co_await codegen.
+enum class MyInt: int {};
+ScalarAwaiter operator co_await(MyInt);
+
+struct MyAgg {
+ AggrAwaiter operator co_await();
+};
+
+// CHECK-LABEL: @TestOpAwait(
+extern "C" void TestOpAwait() {
+ co_await MyInt(42);
+ // CHECK: call void @_Zaw5MyInt(i32 42)
+ // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter* %
+
+ co_await MyAgg{};
+ // CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* %
+ // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %
+}
diff --git a/test/CodeGenCoroutines/coro-builtins.c b/test/CodeGenCoroutines/coro-builtins.c
index 5c3e6c3a6bdf..d18d5e730f91 100644
--- a/test/CodeGenCoroutines/coro-builtins.c
+++ b/test/CodeGenCoroutines/coro-builtins.c
@@ -43,7 +43,7 @@ void f(int n) {
__builtin_coro_free(__builtin_coro_frame());
// CHECK-NEXT: %[[FRAME6:.+]] = call i8* @llvm.coro.frame()
- // CHECK-NEXT: call void @llvm.coro.end(i8* %[[FRAME6]], i1 false)
+ // CHECK-NEXT: call i1 @llvm.coro.end(i8* %[[FRAME6]], i1 false)
__builtin_coro_end(__builtin_coro_frame(), 0);
// CHECK-NEXT: call i8 @llvm.coro.suspend(token none, i1 true)
diff --git a/test/CodeGenCoroutines/coro-cleanup.cpp b/test/CodeGenCoroutines/coro-cleanup.cpp
new file mode 100644
index 000000000000..7f6f35cfe26c
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-cleanup.cpp
@@ -0,0 +1,74 @@
+// Verify that coroutine promise and allocated memory are freed up on exception.
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
+
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
+
+template <class Promise = void> struct coroutine_handle {
+ coroutine_handle() = default;
+ static coroutine_handle from_address(void *) { return {}; }
+};
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) { return {}; }
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) {}
+};
+}
+
+struct suspend_always {
+ bool await_ready();
+ void await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+
+template <> struct std::experimental::coroutine_traits<void> {
+ struct promise_type {
+ void get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void return_void();
+ promise_type();
+ ~promise_type();
+ void unhandled_exception();
+ };
+};
+
+struct Cleanup { ~Cleanup(); };
+void may_throw();
+
+// CHECK: define void @_Z1fv(
+void f() {
+ // CHECK: call i8* @_Znwm(i64
+
+ // If promise constructor throws, check that we free the memory.
+
+ // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeC1Ev(
+ // CHECK-NEXT: to label %{{.+}} unwind label %[[DeallocPad:.+]]
+
+ Cleanup cleanup;
+ may_throw();
+
+ // if may_throw throws, check that we destroy the promise and free the memory.
+
+ // CHECK: invoke void @_Z9may_throwv(
+ // CHECK-NEXT: to label %{{.+}} unwind label %[[PromDtorPad:.+]]
+
+ // CHECK: [[DeallocPad]]:
+ // CHECK-NEXT: landingpad
+ // CHECK-NEXT: cleanup
+ // CHECK: br label %[[Dealloc:.+]]
+
+ // CHECK: [[PromDtorPad]]:
+ // CHECK-NEXT: landingpad
+ // CHECK-NEXT: cleanup
+ // CHECK: call void @_ZN7CleanupD1Ev(%struct.Cleanup*
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeD1Ev(
+ // CHECK: br label %[[Dealloc]]
+
+ // CHECK: [[Dealloc]]:
+ // CHECK: %[[Mem:.+]] = call i8* @llvm.coro.free(
+ // CHECK: call void @_ZdlPv(i8* %[[Mem]])
+
+ co_return;
+}
diff --git a/test/CodeGenCoroutines/coro-eh-cleanup.cpp b/test/CodeGenCoroutines/coro-eh-cleanup.cpp
new file mode 100644
index 000000000000..578d57fbab28
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-eh-cleanup.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm %s -o - -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck --check-prefix=CHECK-LPAD %s
+
+namespace std::experimental {
+template <typename R, typename... T> struct coroutine_traits {
+ using promise_type = typename R::promise_type;
+};
+
+template <class Promise = void> struct coroutine_handle;
+
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) noexcept;
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+template <class Promise> struct coroutine_handle: coroutine_handle<void> {
+ coroutine_handle() = default;
+ static coroutine_handle from_address(void *) noexcept;
+};
+}
+
+struct suspend_always {
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
+};
+
+struct coro_t {
+ struct promise_type {
+ coro_t get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_void() noexcept;
+ void unhandled_exception() noexcept;
+ };
+};
+
+struct Cleanup { ~Cleanup(); };
+void may_throw();
+
+coro_t f() {
+ Cleanup x;
+ may_throw();
+ co_return;
+}
+
+// CHECK: @"\01?f@@YA?AUcoro_t@@XZ"(
+// CHECK: invoke void @"\01?may_throw@@YAXXZ"()
+// CHECK: to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]]
+// CHECK: [[EHCLEANUP]]:
+// CHECK: %[[INNERPAD:.+]] = cleanuppad within none []
+// CHECK: call void @"\01??_DCleanup@@QEAAXXZ"(
+// CHECK: cleanupret from %[[INNERPAD]] unwind label %[[COROENDBB:.+]]
+// CHECK: [[COROENDBB]]:
+// CHECK-NEXT: %[[CLPAD:.+]] = cleanuppad within none
+// CHECK-NEXT: call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %[[CLPAD]]) ]
+// CHECK-NEXT: cleanupret from %[[CLPAD]] unwind label
+
+// CHECK-LPAD: @_Z1fv(
+// CHECK-LPAD: invoke void @_Z9may_throwv()
+// CHECK-LPAD: to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]]
+// CHECK-LPAD: [[EHCLEANUP]]:
+// CHECK-LPAD: landingpad { i8*, i32 }
+// CHECK-LPAD: cleanup
+// CHECK-LPAD: call void @_ZN7CleanupD1Ev(
+// CHECK-LPAD: %[[I1RESUME:.+]] = call i1 @llvm.coro.end(i8* null, i1 true)
+// CHECK-LPAD: br i1 %[[I1RESUME]], label %[[EHRESUME:.+]], label
+// CHECK-LPAD: [[EHRESUME]]:
+// CHECK-LPAD-NEXT: %[[exn:.+]] = load i8*, i8** %exn.slot, align 8
+// CHECK-LPAD-NEXT: %[[sel:.+]] = load i32, i32* %ehselector.slot, align 4
+// CHECK-LPAD-NEXT: %[[val1:.+]] = insertvalue { i8*, i32 } undef, i8* %[[exn]], 0
+// CHECK-LPAD-NEXT: %[[val2:.+]] = insertvalue { i8*, i32 } %[[val1]], i32 %[[sel]], 1
+// CHECK-LPAD-NEXT: resume { i8*, i32 } %[[val2]]
diff --git a/test/CodeGenCoroutines/coro-return.cpp b/test/CodeGenCoroutines/coro-return.cpp
new file mode 100644
index 000000000000..7577725909d0
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-return.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++1z -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
+
+template <class Promise = void> struct coroutine_handle {
+ coroutine_handle() = default;
+ static coroutine_handle from_address(void *) { return {}; }
+};
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) { return {}; }
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) {}
+};
+}
+
+struct suspend_always {
+ bool await_ready();
+ void await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+
+template <> struct std::experimental::coroutine_traits<void> {
+ struct promise_type {
+ void get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void return_void();
+ };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+ // CHECK: %__promise = alloca %"struct.std::experimental::coroutine_traits<void>::promise_type"
+ // CHECK: %call = call i8* @_Znwm(
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type11return_voidEv(%"struct.std::experimental::coroutine_traits<void>::promise_type"* %__promise)
+ // CHECK: call void @_ZdlPv
+ co_return;
+}
+
+template<>
+struct std::experimental::coroutine_traits<int> {
+ struct promise_type {
+ int get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void return_value(int);
+ };
+};
+
+// CHECK-LABEL: f1(
+extern "C" int f1() {
+ // CHECK: %__promise = alloca %"struct.std::experimental::coroutine_traits<int>::promise_type"
+ // CHECK: %call = call i8* @_Znwm(
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type12return_valueEi(%"struct.std::experimental::coroutine_traits<int>::promise_type"* %__promise, i32 42)
+ // CHECK: call void @_ZdlPv
+ co_return 42;
+}
diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m
index f67136b7b226..4bb618c3a415 100644
--- a/test/CodeGenObjC/arc-blocks.m
+++ b/test/CodeGenObjC/arc-blocks.m
@@ -75,7 +75,7 @@ void test3(void (^sink)(id*)) {
// CHECK-NEXT: bitcast i8*
// CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]]
// CHECK-NEXT: [[STRONGPTR1:%.*]] = bitcast i8** [[STRONG]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[STRONGPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[STRONGPTR1]])
// CHECK-NEXT: store i8* null, i8** [[STRONG]]
// CHECK-NEXT: load void (i8**)*, void (i8**)** [[SINK]]
@@ -97,7 +97,7 @@ void test3(void (^sink)(id*)) {
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[STRONG]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[STRONGPTR2:%.*]] = bitcast i8** [[STRONG]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[STRONGPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[STRONGPTR2]])
// CHECK-NEXT: load void (i8**)*, void (i8**)** [[SINK]]
// CHECK-NEXT: bitcast
@@ -172,7 +172,7 @@ void test5(void) {
// CHECK: [[VAR:%.*]] = alloca i8*
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK-NEXT: [[VARPTR1:%.*]] = bitcast i8** [[VAR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[VARPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[VARPTR1]])
// CHECK: [[T0:%.*]] = call i8* @test5_source()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
@@ -185,7 +185,7 @@ void test5(void) {
// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
// CHECK: call void @test5_helper
// CHECK-NEXT: [[VARPTR2:%.*]] = bitcast i8** [[VAR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[VARPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[VARPTR2]])
// CHECK-NEXT: ret void
}
@@ -199,7 +199,7 @@ void test6(void) {
// CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK-NEXT: [[VARPTR1:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 48, i8* [[VARPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 48, i8* [[VARPTR1]])
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[VAR]], i32 0, i32 2
// 0x02000000 - has copy/dispose helpers weak
// CHECK-NEXT: store i32 1107296256, i32* [[T0]]
@@ -218,7 +218,7 @@ void test6(void) {
// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
// CHECK-NEXT: [[VARPTR2:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 48, i8* [[VARPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 48, i8* [[VARPTR2]])
// CHECK-NEXT: ret void
// CHECK-LABEL: define internal void @__Block_byref_object_copy_.{{[0-9]+}}(i8*, i8*) #{{[0-9]+}} {
@@ -506,7 +506,7 @@ void test13(id x) {
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}})
// CHECK-NEXT: store i8* [[T0]], i8** [[X]], align 8
// CHECK-NEXT: [[BPTR1:%.*]] = bitcast void ()** [[B]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[BPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[BPTR1]])
// CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]], align 8
// CHECK-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null
@@ -532,8 +532,6 @@ void test13(id x) {
// CHECK-NEXT: [[T0:%.*]] = load void ()*, void ()** [[B]]
// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // CHECK-NEXT: [[BPTR2:%.*]] = bitcast void ()** [[B]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[BPTR2]])
// CHECK-NEXT: [[T0:%.*]] = load i1, i1* [[CLEANUP_ACTIVE]]
// CHECK-NEXT: br i1 [[T0]]
@@ -541,7 +539,9 @@ void test13(id x) {
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: br label
- // CHECK: [[T0:%.*]] = load i8*, i8** [[X]]
+ // CHECK: [[BPTR2:%.*]] = bitcast void ()** [[B]] to i8*
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[BPTR2]])
+ // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: ret void
}
@@ -566,7 +566,7 @@ void test16() {
// CHECK: [[BLKVAR:%.*]] = alloca void ()*, align 8
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK-NEXT: [[BLKVARPTR1:%.*]] = bitcast void ()** [[BLKVAR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[BLKVARPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[BLKVARPTR1]])
// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: store void ()* null, void ()** [[BLKVAR]], align 8
}
@@ -667,6 +667,41 @@ void test18(id x) {
// CHECK-UNOPT-NEXT: ret void
}
+// Ensure that we don't emit helper code in copy/dispose routines for variables
+// that are const-captured.
+void testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(id x, id y) {
+ id __unsafe_unretained unsafeObject = x;
+ (^ { testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(x, unsafeObject); })();
+}
+
+// CHECK-LABEL: testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke
+// CHECK-UNOPT-LABEL: testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke
+
+// CHECK-UNOPT: @__copy_helper_block
+// CHECK-UNOPT: alloca
+// CHECK-UNOPT-NEXT: alloca
+// CHECK-UNOPT-NEXT: store
+// CHECK-UNOPT-NEXT: store
+// CHECK-UNOPT-NEXT: load
+// CHECK-UNOPT-NEXT: bitcast
+// CHECK-UNOPT-NEXT: load
+// CHECK-UNOPT-NEXT: bitcast
+// CHECK-UNOPT-NEXT: getelementptr
+// CHECK-UNOPT-NEXT: getelementptr
+// CHECK-UNOPT-NEXT: load
+// CHECK-UNOPT-NEXT: store
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong
+// CHECK-UNOPT-NEXT: ret
+
+// CHECK-UNOPT: @__destroy_helper_block
+// CHECK-UNOPT: alloca
+// CHECK-UNOPT-NEXT: store
+// CHECK-UNOPT-NEXT: load
+// CHECK-UNOPT-NEXT: bitcast
+// CHECK-UNOPT-NEXT: getelementptr
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong
+// CHECK-UNOPT-NEXT: ret
+
// rdar://13588325
void test19_sink(void (^)(int));
void test19(void (^b)(void)) {
diff --git a/test/CodeGenObjC/arc-linetable-autorelease.m b/test/CodeGenObjC/arc-linetable-autorelease.m
index 26a779b8d6db..6812e8a6de83 100644
--- a/test/CodeGenObjC/arc-linetable-autorelease.m
+++ b/test/CodeGenObjC/arc-linetable-autorelease.m
@@ -30,11 +30,10 @@ NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h);
// CHECK: define {{.*}}_createBezierPathWithWidth
// CHECK: load {{.*}} %path, align {{.*}}, !dbg ![[RET:[0-9]+]]
// CHECK: call void @objc_storeStrong{{.*}} !dbg ![[ARC:[0-9]+]]
- // CHECK: call {{.*}} @objc_autoreleaseReturnValue{{.*}} !dbg ![[ARC1:[0-9]+]]
+ // CHECK: call {{.*}} @objc_autoreleaseReturnValue{{.*}} !dbg ![[ARC]]
// CHECK: ret {{.*}} !dbg ![[ARC]]
// CHECK: ![[RET]] = !DILocation(line: [[@LINE+1]], scope: !{{.*}})
return path;
- // CHECK: ![[ARC]] = !DILocation(line: [[@LINE+2]], scope: !{{.*}})
- // CHECK: ![[ARC1]] = !DILocation(line: [[@LINE+1]], scope: !{{.*}})
+ // CHECK: ![[ARC]] = !DILocation(line: [[@LINE+1]], scope: !{{.*}})
}
@end
diff --git a/test/CodeGenObjC/arc-precise-lifetime.m b/test/CodeGenObjC/arc-precise-lifetime.m
index eb3111c68a5a..a366c08bbbf6 100644
--- a/test/CodeGenObjC/arc-precise-lifetime.m
+++ b/test/CodeGenObjC/arc-precise-lifetime.m
@@ -8,7 +8,7 @@ void test0() {
x = 0;
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test0_helper()
// CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
@@ -22,7 +22,7 @@ void test0() {
// CHECK-NOT: clang.imprecise_release
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -40,14 +40,14 @@ void test1a_message(void) {
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
// CHECK: [[C:%.*]] = alloca i8*, align 8
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTRPTR1]])
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[CPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
@@ -57,12 +57,12 @@ void test1a_message(void) {
// CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T6]], i8**
// CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[CPTR2]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTRPTR2]])
// CHECK-NEXT: ret void
Test1 *ptr = test1_helper();
char *c = [(ptr) interior];
@@ -74,14 +74,14 @@ void test1a_property(void) {
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
// CHECK: [[C:%.*]] = alloca i8*, align 8
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTRPTR1]])
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[CPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
@@ -91,12 +91,12 @@ void test1a_property(void) {
// CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T6]], i8**
// CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[CPTR2]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTRPTR2]])
// CHECK-NEXT: ret void
Test1 *ptr = test1_helper();
char *c = ptr.interior;
@@ -108,27 +108,27 @@ void test1b_message(void) {
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
// CHECK: [[C:%.*]] = alloca i8*, align 8
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTRPTR1]])
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[CPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T3]], i8**
// CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[CPTR2]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
// CHECK-NOT: clang.imprecise_release
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTRPTR2]])
// CHECK-NEXT: ret void
PRECISE_LIFETIME Test1 *ptr = test1_helper();
char *c = [ptr interior];
@@ -139,27 +139,27 @@ void test1b_property(void) {
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
// CHECK: [[C:%.*]] = alloca i8*, align 8
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTRPTR1]])
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[CPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T3]], i8**
// CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[CPTR2]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
// CHECK-NOT: clang.imprecise_release
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTRPTR2]])
// CHECK-NEXT: ret void
PRECISE_LIFETIME Test1 *ptr = test1_helper();
char *c = ptr.interior;
@@ -170,14 +170,14 @@ void test1c_message(void) {
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
// CHECK: [[PC:%.*]] = alloca i8*, align 8
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTRPTR1]])
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PCPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
@@ -187,12 +187,12 @@ void test1c_message(void) {
// CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T6]], i8**
// CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PCPTR2]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTRPTR2]])
// CHECK-NEXT: ret void
Test1 *ptr = test1_helper();
char *pc = [ptr PropertyReturnsInnerPointer];
@@ -203,14 +203,14 @@ void test1c_property(void) {
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
// CHECK: [[PC:%.*]] = alloca i8*, align 8
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTRPTR1]])
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PCPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
@@ -220,12 +220,12 @@ void test1c_property(void) {
// CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
// CHECK-NEXT: store i8* [[T6]], i8**
// CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PCPTR2]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTRPTR2]])
// CHECK-NEXT: ret void
Test1 *ptr = test1_helper();
char *pc = ptr.PropertyReturnsInnerPointer;
@@ -236,26 +236,26 @@ void test1d_message(void) {
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
// CHECK: [[PC:%.*]] = alloca i8*, align 8
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTRPTR1]])
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PCPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
// CHECK-NEXT: store i8* [[CALL1]], i8**
// CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PCPTR2]])
// CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[TEN]])
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTRPTR2]])
// CHECK-NEXT: ret void
PRECISE_LIFETIME Test1 *ptr = test1_helper();
char *pc = [ptr PropertyReturnsInnerPointer];
@@ -266,26 +266,26 @@ void test1d_property(void) {
// CHECK: [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
// CHECK: [[PC:%.*]] = alloca i8*, align 8
// CHECK: [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTRPTR1]])
// CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
// CHECK-NEXT: store [[TEST1]]* [[T3]]
// CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PCPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
// CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
// CHECK-NEXT: store i8* [[CALL1]], i8**
// CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PCPTR2]])
// CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]*, [[TEST1]]**
// CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[TEN]])
// CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTRPTR2]])
// CHECK-NEXT: ret void
PRECISE_LIFETIME Test1 *ptr = test1_helper();
char *pc = ptr.PropertyReturnsInnerPointer;
diff --git a/test/CodeGenObjC/arc-ternary-op.m b/test/CodeGenObjC/arc-ternary-op.m
index 883fcd366622..3488d2c5387a 100644
--- a/test/CodeGenObjC/arc-ternary-op.m
+++ b/test/CodeGenObjC/arc-ternary-op.m
@@ -11,7 +11,7 @@ void test0(_Bool cond) {
// CHECK-NEXT: zext
// CHECK-NEXT: store
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load i8, i8* [[COND]]
// CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
// CHECK-NEXT: store i1 false, i1* [[RELCOND]]
@@ -32,7 +32,7 @@ void test0(_Bool cond) {
// CHECK: [[T0:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
id x = (cond ? 0 : test0_helper());
}
@@ -54,10 +54,10 @@ void test1(int cond) {
// CHECK-NEXT: [[CONDCLEANUP:%.*]] = alloca i1
// CHECK-NEXT: store i32
// CHECK-NEXT: [[STRONGPTR1:%.*]] = bitcast i8** [[STRONG]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[STRONGPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[STRONGPTR1]])
// CHECK-NEXT: store i8* null, i8** [[STRONG]]
// CHECK-NEXT: [[WEAKPTR1:%.*]] = bitcast i8** [[WEAK]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[WEAKPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[WEAKPTR1]])
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
// CHECK-NEXT: [[T0:%.*]] = load i32, i32* [[COND]]
@@ -102,9 +102,9 @@ void test1(int cond) {
// CHECK: call void @objc_destroyWeak(i8** [[WEAK]])
// CHECK: [[WEAKPTR2:%.*]] = bitcast i8** [[WEAK]] to i8*
- // CHECK: call void @llvm.lifetime.end(i64 8, i8* [[WEAKPTR2]])
+ // CHECK: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[WEAKPTR2]])
// CHECK: [[STRONGPTR2:%.*]] = bitcast i8** [[STRONG]] to i8*
- // CHECK: call void @llvm.lifetime.end(i64 8, i8* [[STRONGPTR2]])
+ // CHECK: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[STRONGPTR2]])
// CHECK: ret void
}
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index 87cf667b4e5e..d34156ee3473 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -1,36 +1,36 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-GLOBALS %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -Wno-incompatible-pointer-types -Wno-arc-unsafe-retained-assign -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -Wno-incompatible-pointer-types -Wno-arc-unsafe-retained-assign -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-GLOBALS %s
// rdar://13129783. Check both native/non-native arc platforms. Here we check
// that they treat nonlazybind differently.
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.6.0 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-ALIEN %s
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.7.0 -triple x86_64-apple-darwin11 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-NATIVE %s
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.6.0 -triple x86_64-apple-darwin10 -Wno-objc-root-class -Wno-incompatible-pointer-types -Wno-arc-unsafe-retained-assign -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-ALIEN %s
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.7.0 -triple x86_64-apple-darwin11 -Wno-objc-root-class -Wno-incompatible-pointer-types -Wno-arc-unsafe-retained-assign -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-NATIVE %s
// ARC-ALIEN: declare extern_weak void @objc_storeStrong(i8**, i8*)
-// ARC-ALIEN: declare extern_weak i8* @objc_retain(i8*)
-// ARC-ALIEN: declare extern_weak i8* @objc_autoreleaseReturnValue(i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_retain(i8* returned)
+// ARC-ALIEN: declare extern_weak i8* @objc_autoreleaseReturnValue(i8* returned)
// ARC-ALIEN: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB:#[0-9]+]]
// ARC-ALIEN: declare extern_weak void @objc_release(i8*)
-// ARC-ALIEN: declare extern_weak i8* @objc_retainAutoreleasedReturnValue(i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_retainAutoreleasedReturnValue(i8* returned)
// ARC-ALIEN: declare extern_weak i8* @objc_initWeak(i8**, i8*)
// ARC-ALIEN: declare extern_weak i8* @objc_storeWeak(i8**, i8*)
// ARC-ALIEN: declare extern_weak i8* @objc_loadWeakRetained(i8**)
// ARC-ALIEN: declare extern_weak void @objc_destroyWeak(i8**)
-// ARC-ALIEN: declare extern_weak i8* @objc_autorelease(i8*)
-// ARC-ALIEN: declare extern_weak i8* @objc_retainAutorelease(i8*)
+// declare extern_weak i8* @objc_autorelease(i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_retainAutorelease(i8* returned)
// ARC-NATIVE: declare void @objc_storeStrong(i8**, i8*)
-// ARC-NATIVE: declare i8* @objc_retain(i8*) [[NLB:#[0-9]+]]
-// ARC-NATIVE: declare i8* @objc_autoreleaseReturnValue(i8*)
+// ARC-NATIVE: declare i8* @objc_retain(i8* returned) [[NLB:#[0-9]+]]
+// ARC-NATIVE: declare i8* @objc_autoreleaseReturnValue(i8* returned)
// ARC-NATIVE: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB]]
// ARC-NATIVE: declare void @objc_release(i8*) [[NLB]]
-// ARC-NATIVE: declare i8* @objc_retainAutoreleasedReturnValue(i8*)
+// ARC-NATIVE: declare i8* @objc_retainAutoreleasedReturnValue(i8* returned)
// ARC-NATIVE: declare i8* @objc_initWeak(i8**, i8*)
// ARC-NATIVE: declare i8* @objc_storeWeak(i8**, i8*)
// ARC-NATIVE: declare i8* @objc_loadWeakRetained(i8**)
// ARC-NATIVE: declare void @objc_destroyWeak(i8**)
-// ARC-NATIVE: declare i8* @objc_autorelease(i8*)
-// ARC-NATIVE: declare i8* @objc_retainAutorelease(i8*)
+// declare i8* @objc_autorelease(i8*)
+// ARC-NATIVE: declare i8* @objc_retainAutorelease(i8* returned)
// CHECK-LABEL: define void @test0
void test0(id x) {
@@ -49,14 +49,14 @@ id test1(id x) {
// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
// CHECK-NEXT: [[YPTR1:%.*]] = bitcast i8** [[Y]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[YPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[YPTR1]])
// CHECK-NEXT: store i8* null, i8** [[Y]]
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T0]])
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[YPTR2:%.*]] = bitcast i8** [[Y]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[YPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[YPTR2]])
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-NEXT: [[T1:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[RET]])
@@ -102,7 +102,7 @@ void test3_unelided() {
// CHECK: [[X:%.*]] = alloca [[TEST3:%.*]]*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast [[TEST3]]** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: store [[TEST3]]* null, [[TEST3]]** [[X]], align
Test3 *x;
@@ -127,7 +127,7 @@ void test3_unelided() {
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast [[TEST3]]** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -135,7 +135,7 @@ void test3_unelided() {
void test3() {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
id x = [[Test3 alloc] initWith: 5];
@@ -171,7 +171,7 @@ void test3() {
// CHECK-NEXT: [[TMP:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]]
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -254,13 +254,13 @@ id test6_helper(void) __attribute__((ns_returns_retained));
void test6() {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test6_helper()
// CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
id x = test6_helper();
}
@@ -270,7 +270,7 @@ void test7_helper(id __attribute__((ns_consumed)));
void test7() {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: store i8* null, i8** [[X]]
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW]]
@@ -278,7 +278,7 @@ void test7() {
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
id x;
test7_helper(x);
@@ -289,12 +289,12 @@ void test8() {
__unsafe_unretained id x = test8_helper();
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: [[T0:%.*]] = call i8* @test8_helper()
// CHECK-NEXT: store i8* [[T0]], i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -309,10 +309,10 @@ void test10() {
// CHECK: [[X:%.*]] = alloca [[TEST10:%.*]]*, align
// CHECK-NEXT: [[Y:%.*]] = alloca i8*, align
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast [[TEST10]]** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: store [[TEST10]]* null, [[TEST10]]** [[X]]
// CHECK-NEXT: [[YPTR1:%.*]] = bitcast i8** [[Y]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[YPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[YPTR1]])
// CHECK-NEXT: load [[TEST10]]*, [[TEST10]]** [[X]], align
// CHECK-NEXT: load i8*, i8** @OBJC_SELECTOR_REFERENCES_{{[0-9]*}}
// CHECK-NEXT: bitcast
@@ -333,12 +333,12 @@ void test10() {
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[YPTR2:%.*]] = bitcast i8** [[Y]] to i8*
- // CHECK-NEXT: void @llvm.lifetime.end(i64 8, i8* [[YPTR2]])
+ // CHECK-NEXT: void @llvm.lifetime.end.p0i8(i64 8, i8* [[YPTR2]])
// CHECK-NEXT: [[T0:%.*]] = load [[TEST10]]*, [[TEST10]]** [[X]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast [[TEST10]]** [[X]] to i8*
- // CHECK-NEXT: void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -348,14 +348,14 @@ void test11(id (*f)(void) __attribute__((ns_returns_retained))) {
// CHECK-NEXT: [[X:%.*]] = alloca i8*, align
// CHECK-NEXT: store i8* ()* {{%.*}}, i8* ()** [[F]], align
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: [[T0:%.*]] = load i8* ()*, i8* ()** [[F]], align
// CHECK-NEXT: [[T1:%.*]] = call i8* [[T0]]()
// CHECK-NEXT: store i8* [[T1]], i8** [[X]], align
// CHECK-NEXT: [[T3:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T3]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
id x = f();
}
@@ -369,7 +369,7 @@ void test12(void) {
__weak id x = test12_helper();
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: [[T0:%.*]] = call i8* @test12_helper()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T1]])
@@ -383,17 +383,17 @@ void test12(void) {
id y = x;
// CHECK-NEXT: [[YPTR1:%.*]] = bitcast i8** [[Y]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[YPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[YPTR1]])
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_loadWeakRetained(i8** [[X]])
// CHECK-NEXT: store i8* [[T2]], i8** [[Y]], align
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[Y]]
// CHECK-NEXT: call void @objc_release(i8* [[T4]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[YPTR2:%.*]] = bitcast i8** [[Y]] to i8*
- // CHECK-NEXT: void @llvm.lifetime.end(i64 8, i8* [[YPTR2]])
+ // CHECK-NEXT: void @llvm.lifetime.end.p0i8(i64 8, i8* [[YPTR2]])
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK: ret void
}
@@ -402,7 +402,7 @@ void test13(void) {
// CHECK-LABEL: define void @test13()
// CHECK: [[X:%.*]] = alloca i8*, align
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: store i8* null, i8** [[X]], align
id x;
@@ -429,7 +429,7 @@ void test13(void) {
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -1005,7 +1005,7 @@ void test37(void) {
// CHECK: [[VAR:%.*]] = alloca [[TEST37:%.*]]*,
// CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
// CHECK-NEXT: [[VARPTR1:%.*]] = bitcast [[TEST37]]** [[VAR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[VARPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[VARPTR1]])
// CHECK-NEXT: store [[TEST37]]* null, [[TEST37]]** [[VAR]]
// CHECK-NEXT: [[W0:%.*]] = load [[TEST37]]*, [[TEST37]]** [[VAR]]
@@ -1027,7 +1027,7 @@ void test37(void) {
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST37]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-NEXT: [[VARPTR2:%.*]] = bitcast [[TEST37]]** [[VAR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[VARPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[VARPTR2]])
// CHECK-NEXT: ret void
}
@@ -1085,7 +1085,7 @@ void test47(void) {
// CHECK-LABEL: define void @test47()
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: store i8* null, i8** [[X]]
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test47_helper()
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
@@ -1099,7 +1099,7 @@ void test47(void) {
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T4]])
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -1109,7 +1109,7 @@ void test48(void) {
// CHECK-LABEL: define void @test48()
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_initWeak(i8** [[X]], i8* null)
// CHECK-NEXT: [[T1:%.*]] = call i8* @test48_helper()
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
@@ -1118,7 +1118,7 @@ void test48(void) {
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -1128,7 +1128,7 @@ void test49(void) {
// CHECK-LABEL: define void @test49()
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: store i8* null, i8** [[X]]
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test49_helper()
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
@@ -1137,7 +1137,7 @@ void test49(void) {
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
// CHECK-NEXT: store i8* [[T3]], i8** [[X]]
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -1174,13 +1174,13 @@ id test52(void) {
// CHECK: [[X:%.*]] = alloca i32
// CHECK-NEXT: [[TMPALLOCA:%.*]] = alloca i8*
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i32* [[X]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* [[XPTR1]])
+// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[XPTR1]])
// CHECK-NEXT: store i32 5, i32* [[X]],
// CHECK-NEXT: [[T0:%.*]] = load i32, i32* [[X]],
// CHECK-NEXT: [[T1:%.*]] = call i8* @test52_helper(i32 [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[TMPALLOCA]]
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i32* [[X]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* [[XPTR2]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[XPTR2]])
// CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[TMPALLOCA]]
// CHECK-NEXT: [[T3:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T2]])
// CHECK-NEXT: ret i8* [[T3]]
@@ -1196,9 +1196,9 @@ void test53(void) {
// CHECK-NEXT: [[Y:%.*]] = alloca i8*,
// CHECK-NEXT: [[TMPALLOCA:%.*]] = alloca i8*,
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK-NEXT: [[YPTR1:%.*]] = bitcast i8** [[Y]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[YPTR1]])
+// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[YPTR1]])
// CHECK-NEXT: [[T0:%.*]] = call i8* @test53_helper()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]],
@@ -1208,14 +1208,14 @@ void test53(void) {
// CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[Y]]
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
// CHECK-NEXT: [[YPTR2:%.*]] = bitcast i8** [[Y]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[YPTR2]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[YPTR2]])
// CHECK-NEXT: [[T3:%.*]] = load i8*, i8** [[TMPALLOCA]]
// CHECK-NEXT: store i8* [[T3]], i8** [[X]],
// CHECK-NEXT: load i8*, i8** [[X]],
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -1263,13 +1263,13 @@ void test56_test(void) {
// CHECK-LABEL: define void @test56_test()
// CHECK: [[X:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK: [[T0:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(
// CHECK-NEXT: store i8* [[T0]], i8** [[X]]
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
@@ -1350,7 +1350,7 @@ void test61(void) {
[test61_make() performSelector: @selector(test61_void)];
// CHECK-NEXT: [[YPTR1:%.*]] = bitcast i8** [[Y]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[YPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[YPTR1]])
// CHECK-NEXT: [[T0:%.*]] = call i8* @test61_make()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: [[T2:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
@@ -1364,7 +1364,7 @@ void test61(void) {
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[YPTR2:%.*]] = bitcast i8** [[Y]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[YPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[YPTR2]])
// CHECK-NEXT: ret void
}
@@ -1378,7 +1378,7 @@ void test62(void) {
extern void test62_body(void);
// CHECK-NEXT: [[IPTR:%.*]] = bitcast i32* [[I]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* [[IPTR]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[IPTR]])
// CHECK-NEXT: store i32 0, i32* [[I]], align 4
// CHECK-NEXT: br label
@@ -1471,11 +1471,11 @@ void test67(void) {
// CHECK-LABEL: define void @test67()
// CHECK: [[CL:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[CLPTR1:%.*]] = bitcast i8** [[CL]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CLPTR1]])
+// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[CLPTR1]])
// CHECK-NEXT: [[T0:%.*]] = call i8* @test67_helper()
// CHECK-NEXT: store i8* [[T0]], i8** [[CL]], align 8
// CHECK-NEXT: [[CLPTR2:%.*]] = bitcast i8** [[CL]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CLPTR2]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[CLPTR2]])
// CHECK-NEXT: ret void
Class test68_helper(void);
@@ -1485,14 +1485,14 @@ void test68(void) {
// CHECK-LABEL: define void @test68()
// CHECK: [[CL:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[CLPTR1:%.*]] = bitcast i8** [[CL]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CLPTR1]])
+// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[CLPTR1]])
// CHECK-NEXT: [[T0:%.*]] = call i8* @test67_helper()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[CL]], align 8
// CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[CL]]
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
// CHECK-NEXT: [[CLPTR2:%.*]] = bitcast i8** [[CL]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CLPTR2]])
+// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[CLPTR2]])
// CHECK-NEXT: ret void
// rdar://problem/10564852
@@ -1504,7 +1504,9 @@ void test68(void) {
// CHECK: [[SELF:%.*]] = alloca [[TEST69:%.*]]*, align 8
// CHECK: [[T0:%.*]] = load [[TEST69]]*, [[TEST69]]** [[SELF]], align 8
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST69]]* [[T0]] to i8*
-// CHECK-NEXT: ret i8* [[T1]]
+// CHECK-NEXT: [[RETAIN:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[AUTORELEASE:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[RETAIN]])
+// CHECK-NEXT: ret i8* [[AUTORELEASE]]
// rdar://problem/10907547
void test70(id i) {
diff --git a/test/CodeGenObjC/availability-cf-link-guard.m b/test/CodeGenObjC/availability-cf-link-guard.m
new file mode 100644
index 000000000000..918d13ffd9f4
--- /dev/null
+++ b/test/CodeGenObjC/availability-cf-link-guard.m
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,CHECK_LINK_OPT %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - -D USE_BUILTIN %s | FileCheck --check-prefixes=CHECK,CHECK_LINK_OPT %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - -D DEF_CF %s | FileCheck --check-prefixes=CHECK_CF,CHECK_LINK_OPT %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK_NO_GUARD %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -emit-llvm -o - %s | FileCheck --check-prefix=CHECK_NO_GUARD %s
+
+#ifdef DEF_CF
+struct CFBundle;
+typedef struct CFBundle *CFBundleRef;
+unsigned CFBundleGetVersionNumber(CFBundleRef bundle);
+// CHECK_CF: declare i32 @CFBundleGetVersionNumber(%struct.CFBundle*)
+// CHECK_CF: @__clang_at_available_requires_core_foundation_framework
+// CHECK_CF-NEXT: call {{.*}}@CFBundleGetVersionNumber
+#endif
+
+void use_at_available() {
+#ifdef DEF_CF
+ CFBundleGetVersionNumber(0);
+#endif
+#ifdef USE_BUILTIN
+ if (__builtin_available(macos 10.12, *))
+ ;
+#else
+ if (@available(macos 10.12, *))
+ ;
+#endif
+}
+
+// CHECK: @llvm.compiler.used{{.*}}@__clang_at_available_requires_core_foundation_framework
+
+// CHECK: declare i32 @CFBundleGetVersionNumber(i8*)
+
+// CHECK-LABEL: linkonce hidden void @__clang_at_available_requires_core_foundation_framework
+// CHECK: call i32 @CFBundleGetVersionNumber(i8* null)
+// CHECK-NEXT: unreachable
+
+// CHECK_NO_GUARD-NOT: __clang_at_available_requires_core_foundation_framework
+// CHECK_NO_GUARD-NOT: CFBundleGetVersionNumber
+
+// CHECK_LINK_OPT: !"Linker Options", ![[OPTS:[0-9]+]]
+// CHECK_LINK_OPT: ![[OPTS]] = !{![[FRAMEWORK:[0-9]+]]
+// CHECK_LINK_OPT: ![[FRAMEWORK]] = !{!"-framework", !"CoreFoundation"}
+
+// CHECK_NO_GUARD-NOT: "Linker Options"
+// CHECK_NO_GUARD-NOT: CoreFoundation
diff --git a/test/CodeGenObjC/availability-check.m b/test/CodeGenObjC/availability-check.m
new file mode 100644
index 000000000000..71c5ff77c96a
--- /dev/null
+++ b/test/CodeGenObjC/availability-check.m
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - %s | FileCheck %s
+
+void use_at_available() {
+ // CHECK: call i32 @__isOSVersionAtLeast(i32 10, i32 12, i32 0)
+ // CHECK-NEXT: icmp ne
+ if (__builtin_available(macos 10.12, *))
+ ;
+
+ // CHECK: call i32 @__isOSVersionAtLeast(i32 10, i32 12, i32 0)
+ // CHECK-NEXT: icmp ne
+ if (@available(macos 10.12, *))
+ ;
+
+ // CHECK: call i32 @__isOSVersionAtLeast(i32 10, i32 12, i32 42)
+ // CHECK-NEXT: icmp ne
+ if (__builtin_available(ios 10, macos 10.12.42, *))
+ ;
+
+ // CHECK-NOT: call i32 @__isOSVersionAtLeast
+ // CHECK: br i1 true
+ if (__builtin_available(ios 10, *))
+ ;
+
+ // This check should be folded: our deployment target is 10.11.
+ // CHECK-NOT: call i32 @__isOSVersionAtLeast
+ // CHECK: br i1 true
+ if (__builtin_available(macos 10.11, *))
+ ;
+}
+
+// CHECK: declare i32 @__isOSVersionAtLeast(i32, i32, i32)
diff --git a/test/CodeGenObjC/empty-collection-literals.m b/test/CodeGenObjC/empty-collection-literals.m
new file mode 100644
index 000000000000..0f9715f521f3
--- /dev/null
+++ b/test/CodeGenObjC/empty-collection-literals.m
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -I %S/Inputs -triple x86_64-apple-macosx10.10.0 -fobjc-runtime=macosx-10.10.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-WITHOUT-EMPTY-COLLECTIONS %s
+// RUN: %clang_cc1 -I %S/Inputs -triple x86_64-apple-macosx10.11.0 -fobjc-runtime=macosx-10.11.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-WITH-EMPTY-COLLECTIONS %s
+
+// RUN: %clang_cc1 -I %S/Inputs -triple arm64-apple-ios8.0 -fobjc-runtime=ios-8.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-WITHOUT-EMPTY-COLLECTIONS %s
+// RUN: %clang_cc1 -I %S/Inputs -triple arm64-apple-ios9.0 -fobjc-runtime=ios-9.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-WITH-EMPTY-COLLECTIONS %s
+
+// RUN: %clang_cc1 -I %S/Inputs -triple armv7k-apple-watchos2.0 -fobjc-runtime=watchos-1.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-WITHOUT-EMPTY-COLLECTIONS %s
+// RUN: %clang_cc1 -I %S/Inputs -triple armv7k-apple-watchos2.0 -fobjc-runtime=watchos-2.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-WITH-EMPTY-COLLECTIONS %s
+
+// RUN: %clang_cc1 -I %S/Inputs -triple arm64-apple-tvos8.0 -fobjc-runtime=ios-8.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-WITHOUT-EMPTY-COLLECTIONS %s
+// RUN: %clang_cc1 -I %S/Inputs -triple arm64-apple-tvos9.0 -fobjc-runtime=ios-9.0 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-WITH-EMPTY-COLLECTIONS %s
+
+#include "literal-support.h"
+
+void test_empty_array() {
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS-LABEL: define void @test_empty_array
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS: {{call.*objc_msgSend}}
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS: {{call.*objc_retainAutoreleasedReturnValue}}
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS: ret void
+
+ // CHECK-WITH-EMPTY-COLLECTIONS-LABEL: define void @test_empty_array
+ // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITH-EMPTY-COLLECTIONS: load {{.*}} @__NSArray0__
+ // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITH-EMPTY-COLLECTIONS: {{call.*objc_retain\(}}
+ // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITH-EMPTY-COLLECTIONS: call void @objc_storeStrong
+ // CHECK-WITH-EMPTY-COLLECTIONS-NEXT: ret void
+ NSArray *arr = @[];
+}
+
+void test_empty_dictionary() {
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS-LABEL: define void @test_empty_dictionary
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS: {{call.*objc_msgSend}}
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS: {{call.*objc_retainAutoreleasedReturnValue}}
+ // CHECK-WITHOUT-EMPTY-COLLECTIONS: ret void
+
+ // CHECK-WITH-EMPTY-COLLECTIONS-LABEL: define void @test_empty_dictionary
+ // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITH-EMPTY-COLLECTIONS: load {{.*}} @__NSDictionary0__
+ // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITH-EMPTY-COLLECTIONS: {{call.*objc_retain\(}}
+ // CHECK-WITH-EMPTY-COLLECTIONS-NOT: ret void
+ // CHECK-WITH-EMPTY-COLLECTIONS: call void @objc_storeStrong
+ // CHECK-WITH-EMPTY-COLLECTIONS-NEXT: ret void
+ NSDictionary *dict = @{};
+}
diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m
index 28515c54f32f..439b9401485f 100644
--- a/test/CodeGenObjC/exceptions.m
+++ b/test/CodeGenObjC/exceptions.m
@@ -83,7 +83,7 @@ void f3() {
// CHECK: [[X:%.*]] = alloca i32
// CHECK: [[XPTR:%.*]] = bitcast i32* [[X]] to i8*
- // CHECK: call void @llvm.lifetime.start(i64 4, i8* nonnull [[XPTR]])
+ // CHECK: call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull [[XPTR]])
// CHECK: store i32 0, i32* [[X]]
int x = 0;
@@ -124,7 +124,7 @@ void f3() {
}
// CHECK: call void @f3_helper(i32 4, i32* nonnull [[X]])
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* nonnull [[XPTR]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[XPTR]])
// CHECK-NEXT: ret void
f3_helper(4, &x);
}
diff --git a/test/CodeGenObjC/ivar-type-encoding.m b/test/CodeGenObjC/ivar-type-encoding.m
new file mode 100644
index 000000000000..ffa5e0d7af0d
--- /dev/null
+++ b/test/CodeGenObjC/ivar-type-encoding.m
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -S -emit-llvm -fobjc-runtime=gcc -o - %s | FileCheck %s
+
+@protocol NSCopying
+@end
+
+@interface NSObject {
+ struct objc_object *isa;
+}
++ (id) new;
+- (id) init;
+@end
+
+@interface NSString : NSObject <NSCopying>
++ (NSString *)foo;
+@end
+
+@interface TestClass : NSObject {
+@public
+ NSString *_stringIvar;
+ int _intIvar;
+}
+@end
+@implementation TestClass
+
+@end
+
+int main() {
+ TestClass *c = [TestClass new];
+ return 0;
+}
+
+// CHECK: @0 = private unnamed_addr constant [12 x i8] c"_stringIvar\00"
+// CHECK: @1 = private unnamed_addr constant [12 x i8] c"@\22NSString\22\00"
+// CHECK: @2 = private unnamed_addr constant [9 x i8] c"_intIvar\00"
+// CHECK: @3 = private unnamed_addr constant [2 x i8] c"i\00"
diff --git a/test/CodeGenObjC/ubsan-bool.m b/test/CodeGenObjC/ubsan-bool.m
index 6d6c08358d07..b30562c4d423 100644
--- a/test/CodeGenObjC/ubsan-bool.m
+++ b/test/CodeGenObjC/ubsan-bool.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=bool %s -o - | FileCheck %s -check-prefixes=SHARED,OBJC
-// RUN: %clang_cc1 -x objective-c++ -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=bool %s -o - | FileCheck %s -check-prefixes=SHARED,OBJC
+// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=bool %s -o - -w | FileCheck %s -check-prefixes=SHARED,OBJC
+// RUN: %clang_cc1 -x objective-c++ -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=bool %s -o - -w | FileCheck %s -check-prefixes=SHARED,OBJC
// RUN: %clang_cc1 -x c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=bool %s -o - | FileCheck %s -check-prefixes=SHARED,C
typedef signed char BOOL;
@@ -10,4 +10,57 @@ BOOL f1() {
// C-NOT: call void @__ubsan_handle_load_invalid_value
BOOL a = 2;
return a + 1;
+ // SHARED: ret i8
}
+
+struct S1 {
+ BOOL b1 : 1;
+};
+
+// SHARED-LABEL: f2
+BOOL f2(struct S1 *s) {
+ // OBJC: [[LOAD:%.*]] = load i8, i8* {{.*}}
+ // OBJC: [[SHL:%.*]] = shl i8 [[LOAD]], 7
+ // OBJC: [[ASHR:%.*]] = ashr i8 [[SHL]], 7
+ // OBJC: icmp ule i8 [[ASHR]], 1, !nosanitize
+ // OBJC: call void @__ubsan_handle_load_invalid_value
+
+ // C-NOT: call void @__ubsan_handle_load_invalid_value
+ return s->b1;
+ // SHARED: ret i8
+}
+
+#ifdef __OBJC__
+@interface I1 {
+@public
+ BOOL b1 : 1;
+}
+@property (nonatomic) BOOL b1;
+@end
+@implementation I1
+@synthesize b1;
+@end
+
+// Check the synthesized getter.
+// OBJC-LABEL: define internal signext i8 @"\01-[I1 b1]"
+// OBJC: [[IVAR:%.*]] = load i64, i64* @"OBJC_IVAR_$_I1.b1"
+// OBJC: [[ADDR:%.*]] = getelementptr inbounds i8, i8* {{.*}}, i64 [[IVAR]]
+// OBJC: [[LOAD:%.*]] = load i8, i8* {{.*}}
+// OBJC: [[SHL:%.*]] = shl i8 [[LOAD]], 7
+// OBJC: [[ASHR:%.*]] = ashr i8 [[SHL]], 7
+// OBJC: icmp ule i8 [[ASHR]], 1, !nosanitize
+// OBJC: call void @__ubsan_handle_load_invalid_value
+
+// Also check direct accesses to the ivar.
+// OBJC-LABEL: f3
+BOOL f3(I1 *i) {
+ // OBJC: [[LOAD:%.*]] = load i8, i8* {{.*}}
+ // OBJC: [[SHL:%.*]] = shl i8 [[LOAD]], 7
+ // OBJC: [[ASHR:%.*]] = ashr i8 [[SHL]], 7
+ // OBJC: icmp ule i8 [[ASHR]], 1, !nosanitize
+ // OBJC: call void @__ubsan_handle_load_invalid_value
+
+ return i->b1;
+ // OBJC: ret i8
+}
+#endif /* __OBJC__ */
diff --git a/test/CodeGenObjC/ubsan-nonnull-and-nullability.m b/test/CodeGenObjC/ubsan-nonnull-and-nullability.m
new file mode 100644
index 000000000000..b927f55cd402
--- /dev/null
+++ b/test/CodeGenObjC/ubsan-nonnull-and-nullability.m
@@ -0,0 +1,31 @@
+// REQUIRES: asserts
+// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-return,returns-nonnull-attribute,nullability-arg,nonnull-attribute %s -o - -w | FileCheck %s
+
+// If both the annotation and the attribute are present, prefer the attribute,
+// since it actually affects IRGen.
+
+// CHECK-LABEL: define nonnull i32* @f1
+__attribute__((returns_nonnull)) int *_Nonnull f1(int *_Nonnull p) {
+ // CHECK: entry:
+ // CHECK-NEXT: [[ADDR:%.*]] = alloca i32*
+ // CHECK-NEXT: store i32* [[P:%.*]], i32** [[ADDR]]
+ // CHECK-NEXT: [[ARG:%.*]] = load i32*, i32** [[ADDR]]
+ // CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32* [[ARG]], null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], label %[[CONT:.+]], label %[[HANDLE:[^,]+]]
+ // CHECK: [[HANDLE]]:
+ // CHECK-NEXT: call void @__ubsan_handle_nonnull_return_abort
+ // CHECK-NEXT: unreachable, !nosanitize
+ // CHECK: [[CONT]]:
+ // CHECK-NEXT: ret i32*
+ return p;
+}
+
+// CHECK-LABEL: define void @f2
+void f2(int *_Nonnull __attribute__((nonnull)) p) {}
+
+// CHECK-LABEL: define void @call_f2
+void call_f2() {
+ // CHECK: call void @__ubsan_handle_nonnull_arg_abort
+ // CHECK-NOT: call void @__ubsan_handle_nonnull_arg_abort
+ f2((void *)0);
+}
diff --git a/test/CodeGenObjC/ubsan-nonnull.m b/test/CodeGenObjC/ubsan-nonnull.m
new file mode 100644
index 000000000000..cc0850caf97f
--- /dev/null
+++ b/test/CodeGenObjC/ubsan-nonnull.m
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nonnull-attribute %s -o - -w | FileCheck %s
+
+@interface A
+
+-(void) one_arg: (__attribute__((nonnull)) int *) arg1;
+
+-(void) varargs: (__attribute__((nonnull)) int *) arg1, ...;
+
++(void) clsmethod: (__attribute__((nonnull)) int *) arg1;
+
+@end
+
+@implementation A
+
+// CHECK-LABEL: define internal void @"\01-[A one_arg:]"
+// CHECK-SAME: i32* nonnull
+-(void) one_arg: (__attribute__((nonnull)) int *) arg1 {}
+
+// CHECK-LABEL: define internal void @"\01-[A varargs:]"
+// CHECK-SAME: i32* nonnull
+-(void) varargs: (__attribute__((nonnull)) int *) arg1, ... {}
+
+// CHECK-LABEL: define internal void @"\01+[A clsmethod:]"
+// CHECK-SAME: i32* nonnull
++(void) clsmethod: (__attribute__((nonnull)) int *) arg1 {}
+
+@end
+
+// CHECK-LABEL: define void @call_A
+void call_A(A *a, int *p) {
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* [[P1:%.*]], null, !nosanitize
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nonnull_arg{{.*}} !nosanitize
+ // CHECK: call void {{.*}} @objc_msgSend {{.*}} ({{.*}}, i32* [[P1]])
+ [a one_arg: p];
+
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* [[P2:%.*]], null, !nosanitize
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nonnull_arg{{.*}} !nosanitize
+ // CHECK: call void {{.*}} @objc_msgSend {{.*}} ({{.*}}, i32* [[P2]], {{.*}})
+ [a varargs: p, p];
+
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* [[P3:%.*]], null, !nosanitize
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nonnull_arg{{.*}} !nosanitize
+ // CHECK: call void {{.*}} @objc_msgSend {{.*}} ({{.*}}, i32* [[P3]])
+ [A clsmethod: p];
+}
diff --git a/test/CodeGenObjC/ubsan-nullability.m b/test/CodeGenObjC/ubsan-nullability.m
new file mode 100644
index 000000000000..457f07136349
--- /dev/null
+++ b/test/CodeGenObjC/ubsan-nullability.m
@@ -0,0 +1,182 @@
+// REQUIRES: asserts
+// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s
+
+// CHECK: [[NONNULL_RV_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 109, i32 1 {{.*}} i32 100, i32 6
+// CHECK: [[NONNULL_ARG_LOC:@.*]] = private unnamed_addr global {{.*}} i32 204, i32 15 {{.*}} i32 190, i32 23
+// CHECK: [[NONNULL_ASSIGN1_LOC:@.*]] = private unnamed_addr global {{.*}} i32 305, i32 9
+// CHECK: [[NONNULL_ASSIGN2_LOC:@.*]] = private unnamed_addr global {{.*}} i32 405, i32 10
+// CHECK: [[NONNULL_ASSIGN3_LOC:@.*]] = private unnamed_addr global {{.*}} i32 505, i32 10
+// CHECK: [[NONNULL_INIT1_LOC:@.*]] = private unnamed_addr global {{.*}} i32 604, i32 25
+// CHECK: [[NONNULL_INIT2_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 707, i32 26
+// CHECK: [[NONNULL_INIT2_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 707, i32 29
+// CHECK: [[NONNULL_RV_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 817, i32 1 {{.*}} i32 800, i32 6
+
+#define NULL ((void *)0)
+
+// CHECK-LABEL: define i32* @nonnull_retval1
+#line 100
+int *_Nonnull nonnull_retval1(int *p) {
+ // CHECK: br i1 true, label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
+ // CHECK: [[NULL]]:
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_return{{.*}}[[NONNULL_RV_LOC1]]
+ return p;
+ // CHECK: [[NONULL]]:
+ // CHECK-NEXT: ret i32*
+}
+
+#line 190
+void nonnull_arg(int *_Nonnull p) {}
+
+// CHECK-LABEL: define void @call_func_with_nonnull_arg
+#line 200
+void call_func_with_nonnull_arg(int *_Nonnull p) {
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_arg{{.*}}[[NONNULL_ARG_LOC]]
+ nonnull_arg(p);
+}
+
+// CHECK-LABEL: define void @nonnull_assign1
+#line 300
+void nonnull_assign1(int *p) {
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_ASSIGN1_LOC]]
+ int *_Nonnull local;
+ local = p;
+}
+
+// CHECK-LABEL: define void @nonnull_assign2
+#line 400
+void nonnull_assign2(int *p) {
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_ASSIGN2_LOC]]
+ int *_Nonnull arr[1];
+ arr[0] = p;
+}
+
+struct S1 {
+ int *_Nonnull mptr;
+};
+
+// CHECK-LABEL: define void @nonnull_assign3
+#line 500
+void nonnull_assign3(int *p) {
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_ASSIGN3_LOC]]
+ struct S1 s;
+ s.mptr = p;
+}
+
+// CHECK-LABEL: define void @nonnull_init1
+#line 600
+void nonnull_init1(int *p) {
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_INIT1_LOC]]
+ int *_Nonnull local = p;
+}
+
+// CHECK-LABEL: define void @nonnull_init2
+#line 700
+void nonnull_init2(int *p) {
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_INIT2_LOC1]]
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_INIT2_LOC2]]
+ int *_Nonnull arr[] = {p, p};
+}
+
+// CHECK-LABEL: define i32* @nonnull_retval2
+#line 800
+int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this.
+ int *_Nonnull arg2, //< Test this.
+ int *_Nullable arg3, //< Don't test the rest.
+ int *arg4,
+ int arg5, ...) {
+ // CHECK: [[ARG1CMP:%.*]] = icmp ne i32* %arg1, null, !nosanitize
+ // CHECK-NEXT: [[DO_RV_CHECK_1:%.*]] = and i1 true, [[ARG1CMP]], !nosanitize
+ // CHECK: [[ARG2CMP:%.*]] = icmp ne i32* %arg2, null, !nosanitize
+ // CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[DO_RV_CHECK_1]], [[ARG2CMP]]
+ // CHECK: br i1 [[DO_RV_CHECK_2]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
+ // CHECK: [[NULL]]:
+ // CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_return{{.*}}[[NONNULL_RV_LOC2]]
+ return arg1;
+ // CHECK: [[NONULL]]:
+ // CHECK-NEXT: ret i32*
+}
+
+@interface A
++(int *_Nonnull) objc_clsmethod: (int *_Nonnull) arg1;
+-(int *_Nonnull) objc_method: (int *_Nonnull) arg1;
+@end
+
+@implementation A
+
+// CHECK-LABEL: define internal i32* @"\01+[A objc_clsmethod:]"
++(int *_Nonnull) objc_clsmethod: (int *_Nonnull) arg1 {
+ // CHECK: [[ARG1CMP:%.*]] = icmp ne i32* %arg1, null, !nosanitize
+ // CHECK-NEXT: [[DO_RV_CHECK:%.*]] = and i1 true, [[ARG1CMP]]
+ // CHECK: br i1 [[DO_RV_CHECK]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
+ // CHECK: [[NULL]]:
+ // CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_return{{.*}}
+ return arg1;
+ // CHECK: [[NONULL]]:
+ // CHECK-NEXT: ret i32*
+}
+
+// CHECK-LABEL: define internal i32* @"\01-[A objc_method:]"
+-(int *_Nonnull) objc_method: (int *_Nonnull) arg1 {
+ // CHECK: [[ARG1CMP:%.*]] = icmp ne i32* %arg1, null, !nosanitize
+ // CHECK-NEXT: [[DO_RV_CHECK:%.*]] = and i1 true, [[ARG1CMP]]
+ // CHECK: br i1 [[DO_RV_CHECK]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
+ // CHECK: [[NULL]]:
+ // CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_return{{.*}}
+ return arg1;
+ // CHECK: [[NONULL]]:
+ // CHECK-NEXT: ret i32*
+}
+@end
+
+// CHECK-LABEL: define void @call_A
+void call_A(A *a, int *p) {
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* [[P1:%.*]], null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_arg{{.*}} !nosanitize
+ // CHECK: call i32* {{.*}} @objc_msgSend to i32* {{.*}}({{.*}}, i32* [[P1]])
+ [a objc_method: p];
+
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* [[P2:%.*]], null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_arg{{.*}} !nosanitize
+ // CHECK: call i32* {{.*}} @objc_msgSend to i32* {{.*}}({{.*}}, i32* [[P2]])
+ [A objc_clsmethod: p];
+}
+
+void dont_crash(int *_Nonnull p, ...) {}
+
+int main() {
+ nonnull_retval1(NULL);
+ nonnull_retval2(NULL, NULL, NULL, NULL, 0, 0, 0, 0);
+ call_func_with_nonnull_arg(NULL);
+ nonnull_assign1(NULL);
+ nonnull_assign2(NULL);
+ nonnull_assign3(NULL);
+ nonnull_init1(NULL);
+ nonnull_init2(NULL);
+ call_A(NULL, NULL);
+ dont_crash(NULL, NULL);
+ return 0;
+}
diff --git a/test/CodeGenObjCXX/arc-attrs-abi.mm b/test/CodeGenObjCXX/arc-attrs-abi.mm
new file mode 100644
index 000000000000..14bdf8be30e5
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-attrs-abi.mm
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple -emit-llvm -fobjc-arc -o - %s -std=c++11 | FileCheck %s --check-prefix=ITANIUM
+// RUN: %clang_cc1 -triple x86_64-windows -emit-llvm -fobjc-arc -o - %s -std=c++11
+//
+// Test cases where we weren't properly adding extended parameter info, which
+// caused assertions to fire. Hence, minimal CHECKs.
+
+struct VirtualBase {
+ VirtualBase(__attribute__((ns_consumed)) id x,
+ void * __attribute__((pass_object_size(0))));
+};
+struct WithVirtualBase : virtual VirtualBase {
+ WithVirtualBase(__attribute__((ns_consumed)) id x);
+};
+
+WithVirtualBase::WithVirtualBase(__attribute__((ns_consumed)) id x)
+ : VirtualBase(x, (void *)0) {}
+
+
+struct VirtualBase2 {
+ VirtualBase2(__attribute__((ns_consumed)) id x, void *y);
+};
+
+// In this case, we don't actually end up passing the `id` param from
+// WithVirtualBaseLast's ctor to WithVirtualBaseMid's. So, we shouldn't emit
+// ext param info for `id` to `Mid`. Itanium-only check since MSABI seems to
+// emit the construction code inline.
+struct WithVirtualBaseMid : virtual VirtualBase2 {
+ // Ensure we only pass in `this` and a vtable. Otherwise this test is useless.
+ // ITANIUM: define {{.*}} void @_ZN18WithVirtualBaseMidCI212VirtualBase2EP11objc_objectPv({{[^,]*}}, {{[^,]*}})
+ using VirtualBase2::VirtualBase2;
+};
+struct WithVirtualBaseLast : WithVirtualBaseMid {
+ using WithVirtualBaseMid::WithVirtualBaseMid;
+};
+
+void callLast(__attribute__((ns_consumed)) id x) {
+ WithVirtualBaseLast{x, (void*)0};
+}
diff --git a/test/CodeGenObjCXX/arc-blocks.mm b/test/CodeGenObjCXX/arc-blocks.mm
index 2bae18a19b3f..1e439578e8e9 100644
--- a/test/CodeGenObjCXX/arc-blocks.mm
+++ b/test/CodeGenObjCXX/arc-blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
// CHECK: [[A:.*]] = type { i64, [10 x i8*] }
diff --git a/test/CodeGenObjCXX/arc-move.mm b/test/CodeGenObjCXX/arc-move.mm
index 7437d6b6c7f9..def2cea95647 100644
--- a/test/CodeGenObjCXX/arc-move.mm
+++ b/test/CodeGenObjCXX/arc-move.mm
@@ -49,7 +49,7 @@ void library_move(__strong id &y) {
// CHECK: [[X:%.*]] = alloca i8*, align 8
// CHECK: [[I:%.*]] = alloca i32, align 4
// CHECK: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XPTR1]])
// CHECK: [[Y:%[a-zA-Z0-9]+]] = call dereferenceable({{[0-9]+}}) i8** @_Z4moveIRU8__strongP11objc_objectEON16remove_referenceIT_E4typeEOS5_
// Load the object
// CHECK-NEXT: [[OBJ:%[a-zA-Z0-9]+]] = load i8*, i8** [[Y]]
@@ -60,15 +60,15 @@ void library_move(__strong id &y) {
id x = move(y);
// CHECK-NEXT: [[IPTR1:%.*]] = bitcast i32* [[I]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* [[IPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[IPTR1]])
// CHECK-NEXT: store i32 17
int i = 17;
// CHECK-NEXT: [[IPTR2:%.*]] = bitcast i32* [[I]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* [[IPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[IPTR2]])
// CHECK-NEXT: [[OBJ:%[a-zA-Z0-9]+]] = load i8*, i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[OBJ]])
// CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[XPTR2]])
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenObjCXX/arc-references.mm b/test/CodeGenObjCXX/arc-references.mm
index c62df4e49bb6..983b211dfbfa 100644
--- a/test/CodeGenObjCXX/arc-references.mm
+++ b/test/CodeGenObjCXX/arc-references.mm
@@ -21,7 +21,7 @@ void test0() {
// CHECK: call void @_Z6calleev
callee();
// CHECK: call void @objc_release
- // CHECK-NEXT: ret
+ // CHECK: ret
}
// No lifetime extension when we're binding a reference to an lvalue.
@@ -44,9 +44,9 @@ void test3() {
const __weak id &ref = strong_id();
// CHECK-NEXT: call void @_Z6calleev()
callee();
- // CHECK-NEXT: [[PTR:%.*]] = bitcast i8*** [[REF]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTR]])
// CHECK-NEXT: call void @objc_destroyWeak
+ // CHECK-NEXT: [[PTR:%.*]] = bitcast i8*** [[REF]] to i8*
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTR]])
// CHECK-NEXT: ret void
}
@@ -75,11 +75,11 @@ void test5(__strong id &x) {
// CHECK-NEXT: [[OBJ_ID:%[a-zA-Z0-9]+]] = bitcast [[A]]* [[OBJ_A]] to i8*
// CHECK-NEXT: call void @objc_release
// CHECK-NEXT: [[IPTR1:%.*]] = bitcast i32* [[I]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* [[IPTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[IPTR1]])
// CHECK-NEXT: store i32 17, i32
int i = 17;
// CHECK-NEXT: [[IPTR2:%.*]] = bitcast i32* [[I]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* [[IPTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[IPTR2]])
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm
index b9d2c4de2fcd..5e66206ad547 100644
--- a/test/CodeGenObjCXX/arc.mm
+++ b/test/CodeGenObjCXX/arc.mm
@@ -65,10 +65,10 @@ void test34(int cond) {
// CHECK-NEXT: [[CONDCLEANUP:%.*]] = alloca i1
// CHECK-NEXT: store i32
// CHECK-NEXT: [[STRONGP:%.*]] = bitcast i8** [[STRONG]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[STRONGP]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[STRONGP]])
// CHECK-NEXT: store i8* null, i8** [[STRONG]]
// CHECK-NEXT: [[WEAKP:%.*]] = bitcast i8** [[WEAK]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[WEAKP]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[WEAKP]])
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
// CHECK-NEXT: [[T0:%.*]] = load i32, i32* [[COND]]
@@ -316,7 +316,7 @@ template void test40_helper<int>();
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
// CHECK-NEXT: [[XP:%.*]] = bitcast i8** [[X]] to i8*
-// CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XP]])
+// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[XP]])
// CHECK-NEXT: store i8* null, i8** [[X]]
// CHECK: [[T0:%.*]] = load i8*, i8** [[X]]
// CHECK-NEXT: store i8* [[T0]], i8** [[TEMP]]
diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm
index 5bb4a1ecfa9b..e4c7618f50c2 100644
--- a/test/CodeGenObjCXX/encode.mm
+++ b/test/CodeGenObjCXX/encode.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=gnu++98 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// CHECK: v17@0:8{vector<float, float, float>=}16
// CHECK: {vector<float, float, float>=}
diff --git a/test/CodeGenObjCXX/lambda-expressions.mm b/test/CodeGenObjCXX/lambda-expressions.mm
index 7ac7a2137fb4..c8247e2e0a26 100644
--- a/test/CodeGenObjCXX/lambda-expressions.mm
+++ b/test/CodeGenObjCXX/lambda-expressions.mm
@@ -71,6 +71,10 @@ void take_block(void (^block)()) { block(); }
// ARC: %[[CAPTURE1:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %[[BLOCK]], i32 0, i32 5
// ARC: store i32 %{{.*}}, i32* %[[CAPTURE1]]
+// ARC-LABEL: define internal void @"_ZZ10-[Foo foo]ENK3$_4clEv"(
+// ARC-NOT: @objc_storeStrong(
+// ARC: ret void
+
// ARC: define internal void @"___ZZN13LambdaCapture4foo1ERiENK3$_3clEv_block_invoke"
// ARC: %[[CAPTURE2:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %{{.*}}, i32 0, i32 5
// ARC: store i32 %{{.*}}, i32* %[[CAPTURE2]]
@@ -124,6 +128,15 @@ namespace BlockInLambda {
};
}
+@interface NSObject @end
+@interface Foo : NSObject @end
+@implementation Foo
+- (void)foo {
+ [&] {
+ ^{ (void)self; }();
+ }();
+}
+@end
// ARC: attributes [[NUW]] = { noinline nounwind{{.*}} }
// MRC: attributes [[NUW]] = { noinline nounwind{{.*}} }
diff --git a/test/CodeGenObjCXX/lambda-to-block.mm b/test/CodeGenObjCXX/lambda-to-block.mm
new file mode 100644
index 000000000000..a8d0718b1244
--- /dev/null
+++ b/test/CodeGenObjCXX/lambda-to-block.mm
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -std=c++1z -emit-llvm -o - %s | FileCheck %s
+
+// rdar://31385153
+// Shouldn't crash!
+
+void takesBlock(void (^)(void));
+
+struct Copyable {
+ Copyable(const Copyable &x);
+};
+
+void hasLambda(Copyable x) {
+ takesBlock([x] () { });
+}
+// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK: call void @"_ZZ9hasLambda8CopyableEN3$_0C1ERKS0_"
+// CHECK-LABEL: define internal void @"_ZZ9hasLambda8CopyableEN3$_0C2ERKS0_"
+// CHECK: call void @_ZN8CopyableC1ERKS_
diff --git a/test/CodeGenObjCXX/literals.mm b/test/CodeGenObjCXX/literals.mm
index 682add3cb531..6a112312bd88 100644
--- a/test/CodeGenObjCXX/literals.mm
+++ b/test/CodeGenObjCXX/literals.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -I %S/Inputs -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -fexceptions -fobjc-exceptions -fcxx-exceptions -fobjc-arc-exceptions -O2 -disable-llvm-passes -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=gnu++98 -I %S/Inputs -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -fexceptions -fobjc-exceptions -fcxx-exceptions -fobjc-arc-exceptions -O2 -disable-llvm-passes -o - %s | FileCheck %s
#include "literal-support.h"
@@ -21,7 +21,7 @@ void test_array() {
// Initializing first element
// CHECK: [[PTR1:%.*]] = bitcast i8** [[ARR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTR1]])
// CHECK: [[ELEMENT0:%[a-zA-Z0-9.]+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[OBJECTS]], i64 0, i64 0
// CHECK-NEXT: call void @_ZN1XC1Ev
// CHECK-NEXT: [[OBJECT0:%[a-zA-Z0-9.]+]] = invoke i8* @_ZNK1XcvP11objc_objectEv
@@ -51,7 +51,7 @@ void test_array() {
// CHECK-NOT: ret void
// CHECK: call void @objc_release
// CHECK-NEXT: [[PTR2:%.*]] = bitcast i8** [[ARR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTR2]])
// CHECK-NEXT: ret void
// Check cleanups
@@ -73,7 +73,7 @@ void test_array_instantiation() {
// Initializing first element
// CHECK: [[PTR1:%.*]] = bitcast i8** [[ARR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PTR1]])
+ // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[PTR1]])
// CHECK: [[ELEMENT0:%[a-zA-Z0-9.]+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[OBJECTS]], i64 0, i64 0
// CHECK-NEXT: call void @_ZN1XC1Ev
// CHECK-NEXT: [[OBJECT0:%[a-zA-Z0-9.]+]] = invoke i8* @_ZNK1XcvP11objc_objectEv
@@ -103,7 +103,7 @@ void test_array_instantiation() {
// CHECK-NOT: ret void
// CHECK: call void @objc_release
// CHECK-NEXT: [[PTR2]] = bitcast i8** [[ARR]] to i8*
- // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTR2]])
+ // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[PTR2]])
// CHECK-NEXT: ret void
// Check cleanups
diff --git a/test/CodeGenObjCXX/objc-weak.mm b/test/CodeGenObjCXX/objc-weak.mm
new file mode 100644
index 000000000000..68c2d4611146
--- /dev/null
+++ b/test/CodeGenObjCXX/objc-weak.mm
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-weak -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s
+
+struct A { __weak id x; };
+
+id test0() {
+ A a;
+ A b = a;
+ A c(static_cast<A&&>(b));
+ a = c;
+ c = static_cast<A&&>(a);
+ return c.x;
+}
+
+// Copy Assignment Operator
+// CHECK-LABEL: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.A* @_ZN1AaSERKS_(
+// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
+// CHECK: [[OBJECTADDR:%.*]] = alloca [[A:.*]]*
+// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
+// CHECK: [[OBJECT:%.*]] = load [[A]]*, [[A]]** [[OBJECTADDR]]
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[OBJECT]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+
+// Move Assignment Operator
+// CHECK-LABEL: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.A* @_ZN1AaSEOS_(
+// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
+// CHECK: [[OBJECTADDR:%.*]] = alloca [[A:.*]]*
+// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
+// CHECK: [[OBJECT:%.*]] = load [[A]]*, [[A]]** [[OBJECTADDR]]
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[OBJECT]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
+
+// Default Constructor
+// CHECK-LABEL: define linkonce_odr void @_ZN1AC2Ev(
+// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
+// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
+// CHECK-NEXT: store i8* null, i8** [[T0]]
+
+// Copy Constructor
+// CHECK-LABEL: define linkonce_odr void @_ZN1AC2ERKS_(
+// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
+// CHECK: [[OBJECTADDR:%.*]] = alloca [[A:.*]]*
+// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
+// CHECK-NEXT: [[OBJECT:%.*]] = load [[A]]*, [[A]]** [[OBJECTADDR]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[OBJECT]], i32 0, i32 0
+// CHECK-NEXT: call void @objc_copyWeak(i8** [[T0]], i8** [[T1]])
+
+// Move Constructor
+// CHECK-LABEL: define linkonce_odr void @_ZN1AC2EOS_(
+// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
+// CHECK: [[OBJECTADDR:%.*]] = alloca [[A:.*]]*
+// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
+// CHECK-NEXT: [[OBJECT:%.*]] = load [[A]]*, [[A]]** [[OBJECTADDR]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[OBJECT]], i32 0, i32 0
+// CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
+
+// Destructor
+// CHECK-LABEL: define linkonce_odr void @_ZN1AD2Ev(
+// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
+// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
+
diff --git a/test/CodeGenObjCXX/objfw-exceptions.mm b/test/CodeGenObjCXX/objfw-exceptions.mm
new file mode 100644
index 000000000000..2c3182f543ac
--- /dev/null
+++ b/test/CodeGenObjCXX/objfw-exceptions.mm
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -fexceptions -fobjc-exceptions -fobjc-runtime=objfw -fcxx-exceptions -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-DWARF
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -fexceptions -fobjc-exceptions -fobjc-runtime=objfw -fcxx-exceptions -fsjlj-exceptions -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-SJLJ
+
+@interface OCType @end
+void opaque();
+
+// CHECK: define void @_Z3foov()
+// CHECK-DWARF-SAME: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_v0 to i8*)
+// CHECK-SJLJ-SAME: personality i8* bitcast (i32 (...)* @__gnu_objc_personality_sj0 to i8*)
+void foo() {
+try {
+// CHECK: invoke void @_Z6opaquev
+opaque();
+} catch (OCType *T) {
+// CHECK: landingpad { i8*, i32 }
+}
+}
diff --git a/test/CodeGenOpenCL/address-space-constant-initializers.cl b/test/CodeGenOpenCL/address-space-constant-initializers.cl
index 45c64c2f716b..a03d939fae54 100644
--- a/test/CodeGenOpenCL/address-space-constant-initializers.cl
+++ b/test/CodeGenOpenCL/address-space-constant-initializers.cl
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple amdgcn-amd-amdhsa-opencl -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple amdgcn-amd-amdhsa-amdgizcl -emit-llvm -o - | FileCheck %s
typedef struct {
int i;
diff --git a/test/CodeGenOpenCL/address-spaces.cl b/test/CodeGenOpenCL/address-spaces.cl
index 3b34986d8936..7c665286547a 100644
--- a/test/CodeGenOpenCL/address-spaces.cl
+++ b/test/CodeGenOpenCL/address-spaces.cl
@@ -1,7 +1,12 @@
-// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 %s -O0 -DCL20 -cl-std=CL2.0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefix=CL20
-
-// CHECK: i32* %arg
+// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,SPIR
+// RUN: %clang_cc1 %s -O0 -DCL20 -cl-std=CL2.0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20SPIR
+// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa-opencl -emit-llvm -o - | FileCheck --check-prefixes=CHECK,SPIR %s
+// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa-opencl -DCL20 -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20SPIR
+// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa-amdgizcl -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,GIZ
+// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa-amdgizcl -DCL20 -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20GIZ
+
+// SPIR: i32* %arg
+// GIZ: i32 addrspace(5)* %arg
void f__p(__private int *arg) {}
// CHECK: i32 addrspace(1)* %arg
@@ -13,7 +18,8 @@ void f__l(__local int *arg) {}
// CHECK: i32 addrspace(2)* %arg
void f__c(__constant int *arg) {}
-// CHECK: i32* %arg
+// SPIR: i32* %arg
+// GIZ: i32 addrspace(5)* %arg
void fp(private int *arg) {}
// CHECK: i32 addrspace(1)* %arg
@@ -29,16 +35,21 @@ void fc(constant int *arg) {}
int i;
// CL20-DAG: @i = common addrspace(1) global i32 0
int *ptr;
-// CL20-DAG: @ptr = common addrspace(1) global i32 addrspace(4)* null
+// CL20SPIR-DAG: @ptr = common addrspace(1) global i32 addrspace(4)* null
+// CL20GIZ-DAG: @ptr = common addrspace(1) global i32* null
#endif
-// CHECK: i32* %arg
-// CL20-DAG: i32 addrspace(4)* %arg
+// SPIR: i32* %arg
+// GIZ: i32 addrspace(5)* %arg
+// CL20SPIR-DAG: i32 addrspace(4)* %arg
+// CL20GIZ-DAG: i32* %arg
void f(int *arg) {
int i;
-// CHECK: %i = alloca i32,
-// CL20-DAG: %i = alloca i32,
+// SPIR: %i = alloca i32,
+// GIZ: %i = alloca i32{{.*}}addrspace(5)
+// CL20SPIR-DAG: %i = alloca i32,
+// CL20GIZ-DAG: %i = alloca i32{{.*}}addrspace(5)
#ifdef CL20
static int ii;
diff --git a/test/CodeGenOpenCL/amdgcn-large-globals.cl b/test/CodeGenOpenCL/amdgcn-large-globals.cl
new file mode 100644
index 000000000000..ea9ea618a488
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgcn-large-globals.cl
@@ -0,0 +1,12 @@
+// REQUIRES: amdgpu-registered-target
+// RUN: %clang_cc1 -cl-std=CL2.0 -triple amdgcn-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @One = common local_unnamed_addr addrspace(1) global [6442450944 x i8] zeroinitializer, align 1
+unsigned char One[6442450944];
+// CHECK: @Two = common local_unnamed_addr addrspace(1) global [6442450944 x i32] zeroinitializer, align 4
+global unsigned int Two[6442450944];
+
+kernel void large_globals(unsigned int id) {
+ One[id] = id;
+ Two[id + 1] = id + 1;
+}
diff --git a/test/CodeGenOpenCL/amdgpu-alignment.cl b/test/CodeGenOpenCL/amdgpu-alignment.cl
new file mode 100644
index 000000000000..35a8342eec01
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgpu-alignment.cl
@@ -0,0 +1,522 @@
+// REQUIRES: amdgpu-registered-target
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -S -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
+
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+typedef char __attribute__((ext_vector_type(2))) char2;
+typedef char __attribute__((ext_vector_type(3))) char3;
+typedef char __attribute__((ext_vector_type(4))) char4;
+typedef char __attribute__((ext_vector_type(8))) char8;
+typedef char __attribute__((ext_vector_type(16))) char16;
+
+typedef short __attribute__((ext_vector_type(2))) short2;
+typedef short __attribute__((ext_vector_type(3))) short3;
+typedef short __attribute__((ext_vector_type(4))) short4;
+typedef short __attribute__((ext_vector_type(8))) short8;
+typedef short __attribute__((ext_vector_type(16))) short16;
+
+typedef int __attribute__((ext_vector_type(2))) int2;
+typedef int __attribute__((ext_vector_type(3))) int3;
+typedef int __attribute__((ext_vector_type(4))) int4;
+typedef int __attribute__((ext_vector_type(8))) int8;
+typedef int __attribute__((ext_vector_type(16))) int16;
+
+typedef long __attribute__((ext_vector_type(2))) long2;
+typedef long __attribute__((ext_vector_type(3))) long3;
+typedef long __attribute__((ext_vector_type(4))) long4;
+typedef long __attribute__((ext_vector_type(8))) long8;
+typedef long __attribute__((ext_vector_type(16))) long16;
+
+typedef half __attribute__((ext_vector_type(2))) half2;
+typedef half __attribute__((ext_vector_type(3))) half3;
+typedef half __attribute__((ext_vector_type(4))) half4;
+typedef half __attribute__((ext_vector_type(8))) half8;
+typedef half __attribute__((ext_vector_type(16))) half16;
+
+typedef float __attribute__((ext_vector_type(2))) float2;
+typedef float __attribute__((ext_vector_type(3))) float3;
+typedef float __attribute__((ext_vector_type(4))) float4;
+typedef float __attribute__((ext_vector_type(8))) float8;
+typedef float __attribute__((ext_vector_type(16))) float16;
+
+typedef double __attribute__((ext_vector_type(2))) double2;
+typedef double __attribute__((ext_vector_type(3))) double3;
+typedef double __attribute__((ext_vector_type(4))) double4;
+typedef double __attribute__((ext_vector_type(8))) double8;
+typedef double __attribute__((ext_vector_type(16))) double16;
+
+// CHECK: @local_memory_alignment_global.lds_i8 = internal addrspace(3) global [4 x i8] undef, align 1
+// CHECK: @local_memory_alignment_global.lds_v2i8 = internal addrspace(3) global [4 x <2 x i8>] undef, align 2
+// CHECK: @local_memory_alignment_global.lds_v3i8 = internal addrspace(3) global [4 x <3 x i8>] undef, align 4
+// CHECK: @local_memory_alignment_global.lds_v4i8 = internal addrspace(3) global [4 x <4 x i8>] undef, align 4
+// CHECK: @local_memory_alignment_global.lds_v8i8 = internal addrspace(3) global [4 x <8 x i8>] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v16i8 = internal addrspace(3) global [4 x <16 x i8>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_i16 = internal addrspace(3) global [4 x i16] undef, align 2
+// CHECK: @local_memory_alignment_global.lds_v2i16 = internal addrspace(3) global [4 x <2 x i16>] undef, align 4
+// CHECK: @local_memory_alignment_global.lds_v3i16 = internal addrspace(3) global [4 x <3 x i16>] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v4i16 = internal addrspace(3) global [4 x <4 x i16>] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v8i16 = internal addrspace(3) global [4 x <8 x i16>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_v16i16 = internal addrspace(3) global [4 x <16 x i16>] undef, align 32
+// CHECK: @local_memory_alignment_global.lds_i32 = internal addrspace(3) global [4 x i32] undef, align 4
+// CHECK: @local_memory_alignment_global.lds_v2i32 = internal addrspace(3) global [4 x <2 x i32>] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v3i32 = internal addrspace(3) global [4 x <3 x i32>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_v4i32 = internal addrspace(3) global [4 x <4 x i32>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_v8i32 = internal addrspace(3) global [4 x <8 x i32>] undef, align 32
+// CHECK: @local_memory_alignment_global.lds_v16i32 = internal addrspace(3) global [4 x <16 x i32>] undef, align 64
+// CHECK: @local_memory_alignment_global.lds_i64 = internal addrspace(3) global [4 x i64] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v2i64 = internal addrspace(3) global [4 x <2 x i64>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_v3i64 = internal addrspace(3) global [4 x <3 x i64>] undef, align 32
+// CHECK: @local_memory_alignment_global.lds_v4i64 = internal addrspace(3) global [4 x <4 x i64>] undef, align 32
+// CHECK: @local_memory_alignment_global.lds_v8i64 = internal addrspace(3) global [4 x <8 x i64>] undef, align 64
+// CHECK: @local_memory_alignment_global.lds_v16i64 = internal addrspace(3) global [4 x <16 x i64>] undef, align 128
+// CHECK: @local_memory_alignment_global.lds_f16 = internal addrspace(3) global [4 x half] undef, align 2
+// CHECK: @local_memory_alignment_global.lds_v2f16 = internal addrspace(3) global [4 x <2 x half>] undef, align 4
+// CHECK: @local_memory_alignment_global.lds_v3f16 = internal addrspace(3) global [4 x <3 x half>] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v4f16 = internal addrspace(3) global [4 x <4 x half>] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v8f16 = internal addrspace(3) global [4 x <8 x half>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_v16f16 = internal addrspace(3) global [4 x <16 x half>] undef, align 32
+// CHECK: @local_memory_alignment_global.lds_f32 = internal addrspace(3) global [4 x float] undef, align 4
+// CHECK: @local_memory_alignment_global.lds_v2f32 = internal addrspace(3) global [4 x <2 x float>] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v3f32 = internal addrspace(3) global [4 x <3 x float>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_v4f32 = internal addrspace(3) global [4 x <4 x float>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_v8f32 = internal addrspace(3) global [4 x <8 x float>] undef, align 32
+// CHECK: @local_memory_alignment_global.lds_v16f32 = internal addrspace(3) global [4 x <16 x float>] undef, align 64
+// CHECK: @local_memory_alignment_global.lds_f64 = internal addrspace(3) global [4 x double] undef, align 8
+// CHECK: @local_memory_alignment_global.lds_v2f64 = internal addrspace(3) global [4 x <2 x double>] undef, align 16
+// CHECK: @local_memory_alignment_global.lds_v3f64 = internal addrspace(3) global [4 x <3 x double>] undef, align 32
+// CHECK: @local_memory_alignment_global.lds_v4f64 = internal addrspace(3) global [4 x <4 x double>] undef, align 32
+// CHECK: @local_memory_alignment_global.lds_v8f64 = internal addrspace(3) global [4 x <8 x double>] undef, align 64
+// CHECK: @local_memory_alignment_global.lds_v16f64 = internal addrspace(3) global [4 x <16 x double>] undef, align 128
+
+
+// CHECK-LABEL: @local_memory_alignment_global(
+// CHECK: store volatile i8 0, i8 addrspace(3)* getelementptr inbounds ([4 x i8], [4 x i8] addrspace(3)* @local_memory_alignment_global.lds_i8, i32 0, i32 0), align 1
+// CHECK: store volatile <2 x i8> zeroinitializer, <2 x i8> addrspace(3)* getelementptr inbounds ([4 x <2 x i8>], [4 x <2 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v2i8, i32 0, i32 0), align 2
+// CHECK: store volatile <4 x i8> <i8 0, i8 0, i8 0, i8 undef>, <4 x i8> addrspace(3)* bitcast ([4 x <3 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v3i8 to <4 x i8> addrspace(3)*), align 4
+// CHECK: store volatile <4 x i8> zeroinitializer, <4 x i8> addrspace(3)* getelementptr inbounds ([4 x <4 x i8>], [4 x <4 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v4i8, i32 0, i32 0), align 4
+// CHECK: store volatile <8 x i8> zeroinitializer, <8 x i8> addrspace(3)* getelementptr inbounds ([4 x <8 x i8>], [4 x <8 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v8i8, i32 0, i32 0), align 8
+// CHECK: store volatile <16 x i8> zeroinitializer, <16 x i8> addrspace(3)* getelementptr inbounds ([4 x <16 x i8>], [4 x <16 x i8>] addrspace(3)* @local_memory_alignment_global.lds_v16i8, i32 0, i32 0), align 16
+// CHECK: store volatile i16 0, i16 addrspace(3)* getelementptr inbounds ([4 x i16], [4 x i16] addrspace(3)* @local_memory_alignment_global.lds_i16, i32 0, i32 0), align 2
+// CHECK: store volatile <2 x i16> zeroinitializer, <2 x i16> addrspace(3)* getelementptr inbounds ([4 x <2 x i16>], [4 x <2 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v2i16, i32 0, i32 0), align 4
+// CHECK: store volatile <4 x i16> <i16 0, i16 0, i16 0, i16 undef>, <4 x i16> addrspace(3)* bitcast ([4 x <3 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v3i16 to <4 x i16> addrspace(3)*), align 8
+// CHECK: store volatile <4 x i16> zeroinitializer, <4 x i16> addrspace(3)* getelementptr inbounds ([4 x <4 x i16>], [4 x <4 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v4i16, i32 0, i32 0), align 8
+// CHECK: store volatile <8 x i16> zeroinitializer, <8 x i16> addrspace(3)* getelementptr inbounds ([4 x <8 x i16>], [4 x <8 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v8i16, i32 0, i32 0), align 16
+// CHECK: store volatile <16 x i16> zeroinitializer, <16 x i16> addrspace(3)* getelementptr inbounds ([4 x <16 x i16>], [4 x <16 x i16>] addrspace(3)* @local_memory_alignment_global.lds_v16i16, i32 0, i32 0), align 32
+// CHECK: store volatile i32 0, i32 addrspace(3)* getelementptr inbounds ([4 x i32], [4 x i32] addrspace(3)* @local_memory_alignment_global.lds_i32, i32 0, i32 0), align 4
+// CHECK: store volatile <2 x i32> zeroinitializer, <2 x i32> addrspace(3)* getelementptr inbounds ([4 x <2 x i32>], [4 x <2 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v2i32, i32 0, i32 0), align 8
+// CHECK: store volatile <4 x i32> <i32 0, i32 0, i32 0, i32 undef>, <4 x i32> addrspace(3)* bitcast ([4 x <3 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v3i32 to <4 x i32> addrspace(3)*), align 16
+// CHECK: store volatile <4 x i32> zeroinitializer, <4 x i32> addrspace(3)* getelementptr inbounds ([4 x <4 x i32>], [4 x <4 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v4i32, i32 0, i32 0), align 16
+// CHECK: store volatile <8 x i32> zeroinitializer, <8 x i32> addrspace(3)* getelementptr inbounds ([4 x <8 x i32>], [4 x <8 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v8i32, i32 0, i32 0), align 32
+// CHECK: store volatile <16 x i32> zeroinitializer, <16 x i32> addrspace(3)* getelementptr inbounds ([4 x <16 x i32>], [4 x <16 x i32>] addrspace(3)* @local_memory_alignment_global.lds_v16i32, i32 0, i32 0), align 64
+// CHECK: store volatile i64 0, i64 addrspace(3)* getelementptr inbounds ([4 x i64], [4 x i64] addrspace(3)* @local_memory_alignment_global.lds_i64, i32 0, i32 0), align 8
+// CHECK: store volatile <2 x i64> zeroinitializer, <2 x i64> addrspace(3)* getelementptr inbounds ([4 x <2 x i64>], [4 x <2 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v2i64, i32 0, i32 0), align 16
+// CHECK: store volatile <4 x i64> <i64 0, i64 0, i64 0, i64 undef>, <4 x i64> addrspace(3)* bitcast ([4 x <3 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v3i64 to <4 x i64> addrspace(3)*), align 32
+// CHECK: store volatile <4 x i64> zeroinitializer, <4 x i64> addrspace(3)* getelementptr inbounds ([4 x <4 x i64>], [4 x <4 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v4i64, i32 0, i32 0), align 32
+// CHECK: store volatile <8 x i64> zeroinitializer, <8 x i64> addrspace(3)* getelementptr inbounds ([4 x <8 x i64>], [4 x <8 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v8i64, i32 0, i32 0), align 64
+// CHECK: store volatile <16 x i64> zeroinitializer, <16 x i64> addrspace(3)* getelementptr inbounds ([4 x <16 x i64>], [4 x <16 x i64>] addrspace(3)* @local_memory_alignment_global.lds_v16i64, i32 0, i32 0), align 128
+// CHECK: store volatile half 0xH0000, half addrspace(3)* getelementptr inbounds ([4 x half], [4 x half] addrspace(3)* @local_memory_alignment_global.lds_f16, i32 0, i32 0), align 2
+// CHECK: store volatile <2 x half> zeroinitializer, <2 x half> addrspace(3)* getelementptr inbounds ([4 x <2 x half>], [4 x <2 x half>] addrspace(3)* @local_memory_alignment_global.lds_v2f16, i32 0, i32 0), align 4
+// CHECK: store volatile <4 x half> <half 0xH0000, half 0xH0000, half 0xH0000, half undef>, <4 x half> addrspace(3)* bitcast ([4 x <3 x half>] addrspace(3)* @local_memory_alignment_global.lds_v3f16 to <4 x half> addrspace(3)*), align 8
+// CHECK: store volatile <4 x half> zeroinitializer, <4 x half> addrspace(3)* getelementptr inbounds ([4 x <4 x half>], [4 x <4 x half>] addrspace(3)* @local_memory_alignment_global.lds_v4f16, i32 0, i32 0), align 8
+// CHECK: store volatile <8 x half> zeroinitializer, <8 x half> addrspace(3)* getelementptr inbounds ([4 x <8 x half>], [4 x <8 x half>] addrspace(3)* @local_memory_alignment_global.lds_v8f16, i32 0, i32 0), align 16
+// CHECK: store volatile <16 x half> zeroinitializer, <16 x half> addrspace(3)* getelementptr inbounds ([4 x <16 x half>], [4 x <16 x half>] addrspace(3)* @local_memory_alignment_global.lds_v16f16, i32 0, i32 0), align 32
+// CHECK: store volatile float 0.000000e+00, float addrspace(3)* getelementptr inbounds ([4 x float], [4 x float] addrspace(3)* @local_memory_alignment_global.lds_f32, i32 0, i32 0), align 4
+// CHECK: store volatile <2 x float> zeroinitializer, <2 x float> addrspace(3)* getelementptr inbounds ([4 x <2 x float>], [4 x <2 x float>] addrspace(3)* @local_memory_alignment_global.lds_v2f32, i32 0, i32 0), align 8
+// CHECK: store volatile <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float undef>, <4 x float> addrspace(3)* bitcast ([4 x <3 x float>] addrspace(3)* @local_memory_alignment_global.lds_v3f32 to <4 x float> addrspace(3)*), align 16
+// CHECK: store volatile <4 x float> zeroinitializer, <4 x float> addrspace(3)* getelementptr inbounds ([4 x <4 x float>], [4 x <4 x float>] addrspace(3)* @local_memory_alignment_global.lds_v4f32, i32 0, i32 0), align 16
+// CHECK: store volatile <8 x float> zeroinitializer, <8 x float> addrspace(3)* getelementptr inbounds ([4 x <8 x float>], [4 x <8 x float>] addrspace(3)* @local_memory_alignment_global.lds_v8f32, i32 0, i32 0), align 32
+// CHECK: store volatile <16 x float> zeroinitializer, <16 x float> addrspace(3)* getelementptr inbounds ([4 x <16 x float>], [4 x <16 x float>] addrspace(3)* @local_memory_alignment_global.lds_v16f32, i32 0, i32 0), align 64
+// CHECK: store volatile double 0.000000e+00, double addrspace(3)* getelementptr inbounds ([4 x double], [4 x double] addrspace(3)* @local_memory_alignment_global.lds_f64, i32 0, i32 0), align 8
+// CHECK: store volatile <2 x double> zeroinitializer, <2 x double> addrspace(3)* getelementptr inbounds ([4 x <2 x double>], [4 x <2 x double>] addrspace(3)* @local_memory_alignment_global.lds_v2f64, i32 0, i32 0), align 16
+// CHECK: store volatile <4 x double> <double 0.000000e+00, double 0.000000e+00, double 0.000000e+00, double undef>, <4 x double> addrspace(3)* bitcast ([4 x <3 x double>] addrspace(3)* @local_memory_alignment_global.lds_v3f64 to <4 x double> addrspace(3)*), align 32
+// CHECK: store volatile <4 x double> zeroinitializer, <4 x double> addrspace(3)* getelementptr inbounds ([4 x <4 x double>], [4 x <4 x double>] addrspace(3)* @local_memory_alignment_global.lds_v4f64, i32 0, i32 0), align 32
+// CHECK: store volatile <8 x double> zeroinitializer, <8 x double> addrspace(3)* getelementptr inbounds ([4 x <8 x double>], [4 x <8 x double>] addrspace(3)* @local_memory_alignment_global.lds_v8f64, i32 0, i32 0), align 64
+// CHECK: store volatile <16 x double> zeroinitializer, <16 x double> addrspace(3)* getelementptr inbounds ([4 x <16 x double>], [4 x <16 x double>] addrspace(3)* @local_memory_alignment_global.lds_v16f64, i32 0, i32 0), align 128
+kernel void local_memory_alignment_global()
+{
+ volatile local char lds_i8[4];
+ volatile local char2 lds_v2i8[4];
+ volatile local char3 lds_v3i8[4];
+ volatile local char4 lds_v4i8[4];
+ volatile local char8 lds_v8i8[4];
+ volatile local char16 lds_v16i8[4];
+
+ volatile local short lds_i16[4];
+ volatile local short2 lds_v2i16[4];
+ volatile local short3 lds_v3i16[4];
+ volatile local short4 lds_v4i16[4];
+ volatile local short8 lds_v8i16[4];
+ volatile local short16 lds_v16i16[4];
+
+ volatile local int lds_i32[4];
+ volatile local int2 lds_v2i32[4];
+ volatile local int3 lds_v3i32[4];
+ volatile local int4 lds_v4i32[4];
+ volatile local int8 lds_v8i32[4];
+ volatile local int16 lds_v16i32[4];
+
+ volatile local long lds_i64[4];
+ volatile local long2 lds_v2i64[4];
+ volatile local long3 lds_v3i64[4];
+ volatile local long4 lds_v4i64[4];
+ volatile local long8 lds_v8i64[4];
+ volatile local long16 lds_v16i64[4];
+
+ volatile local half lds_f16[4];
+ volatile local half2 lds_v2f16[4];
+ volatile local half3 lds_v3f16[4];
+ volatile local half4 lds_v4f16[4];
+ volatile local half8 lds_v8f16[4];
+ volatile local half16 lds_v16f16[4];
+
+ volatile local float lds_f32[4];
+ volatile local float2 lds_v2f32[4];
+ volatile local float3 lds_v3f32[4];
+ volatile local float4 lds_v4f32[4];
+ volatile local float8 lds_v8f32[4];
+ volatile local float16 lds_v16f32[4];
+
+ volatile local double lds_f64[4];
+ volatile local double2 lds_v2f64[4];
+ volatile local double3 lds_v3f64[4];
+ volatile local double4 lds_v4f64[4];
+ volatile local double8 lds_v8f64[4];
+ volatile local double16 lds_v16f64[4];
+
+ *lds_i8 = 0;
+ *lds_v2i8 = 0;
+ *lds_v3i8 = 0;
+ *lds_v4i8 = 0;
+ *lds_v8i8 = 0;
+ *lds_v16i8 = 0;
+
+ *lds_i16 = 0;
+ *lds_v2i16 = 0;
+ *lds_v3i16 = 0;
+ *lds_v4i16 = 0;
+ *lds_v8i16 = 0;
+ *lds_v16i16 = 0;
+
+ *lds_i32 = 0;
+ *lds_v2i32 = 0;
+ *lds_v3i32 = 0;
+ *lds_v4i32 = 0;
+ *lds_v8i32 = 0;
+ *lds_v16i32 = 0;
+
+ *lds_i64 = 0;
+ *lds_v2i64 = 0;
+ *lds_v3i64 = 0;
+ *lds_v4i64 = 0;
+ *lds_v8i64 = 0;
+ *lds_v16i64 = 0;
+
+ *lds_f16 = 0;
+ *lds_v2f16 = 0;
+ *lds_v3f16 = 0;
+ *lds_v4f16 = 0;
+ *lds_v8f16 = 0;
+ *lds_v16f16 = 0;
+
+ *lds_f32 = 0;
+ *lds_v2f32 = 0;
+ *lds_v3f32 = 0;
+ *lds_v4f32 = 0;
+ *lds_v8f32 = 0;
+ *lds_v16f32 = 0;
+
+ *lds_f64 = 0;
+ *lds_v2f64 = 0;
+ *lds_v3f64 = 0;
+ *lds_v4f64 = 0;
+ *lds_v8f64 = 0;
+ *lds_v16f64 = 0;
+}
+
+kernel void local_memory_alignment_arg(
+ volatile local char* lds_i8,
+ volatile local char2* lds_v2i8,
+ volatile local char3* lds_v3i8,
+ volatile local char4* lds_v4i8,
+ volatile local char8* lds_v8i8,
+ volatile local char16* lds_v16i8,
+
+ volatile local short* lds_i16,
+ volatile local short2* lds_v2i16,
+ volatile local short3* lds_v3i16,
+ volatile local short4* lds_v4i16,
+ volatile local short8* lds_v8i16,
+ volatile local short16* lds_v16i16,
+
+ volatile local int* lds_i32,
+ volatile local int2* lds_v2i32,
+ volatile local int3* lds_v3i32,
+ volatile local int4* lds_v4i32,
+ volatile local int8* lds_v8i32,
+ volatile local int16* lds_v16i32,
+
+ volatile local long* lds_i64,
+ volatile local long2* lds_v2i64,
+ volatile local long3* lds_v3i64,
+ volatile local long4* lds_v4i64,
+ volatile local long8* lds_v8i64,
+ volatile local long16* lds_v16i64,
+
+ volatile local half* lds_f16,
+ volatile local half2* lds_v2f16,
+ volatile local half3* lds_v3f16,
+ volatile local half4* lds_v4f16,
+ volatile local half8* lds_v8f16,
+ volatile local half16* lds_v16f16,
+
+ volatile local float* lds_f32,
+ volatile local float2* lds_v2f32,
+ volatile local float3* lds_v3f32,
+ volatile local float4* lds_v4f32,
+ volatile local float8* lds_v8f32,
+ volatile local float16* lds_v16f32,
+
+ volatile local double* lds_f64,
+ volatile local double2* lds_v2f64,
+ volatile local double3* lds_v3f64,
+ volatile local double4* lds_v4f64,
+ volatile local double8* lds_v8f64,
+ volatile local double16* lds_v16f64)
+{
+ *lds_i8 = 0;
+ *lds_v2i8 = 0;
+ *lds_v3i8 = 0;
+ *lds_v4i8 = 0;
+ *lds_v8i8 = 0;
+ *lds_v16i8 = 0;
+
+ *lds_i16 = 0;
+ *lds_v2i16 = 0;
+ *lds_v3i16 = 0;
+ *lds_v4i16 = 0;
+ *lds_v8i16 = 0;
+ *lds_v16i16 = 0;
+
+ *lds_i32 = 0;
+ *lds_v2i32 = 0;
+ *lds_v3i32 = 0;
+ *lds_v4i32 = 0;
+ *lds_v8i32 = 0;
+ *lds_v16i32 = 0;
+
+ *lds_i64 = 0;
+ *lds_v2i64 = 0;
+ *lds_v3i64 = 0;
+ *lds_v4i64 = 0;
+ *lds_v8i64 = 0;
+ *lds_v16i64 = 0;
+
+ *lds_f16 = 0;
+ *lds_v2f16 = 0;
+ *lds_v3f16 = 0;
+ *lds_v4f16 = 0;
+ *lds_v8f16 = 0;
+ *lds_v16f16 = 0;
+
+ *lds_f32 = 0;
+ *lds_v2f32 = 0;
+ *lds_v3f32 = 0;
+ *lds_v4f32 = 0;
+ *lds_v8f32 = 0;
+ *lds_v16f32 = 0;
+
+ *lds_f64 = 0;
+ *lds_v2f64 = 0;
+ *lds_v3f64 = 0;
+ *lds_v4f64 = 0;
+ *lds_v8f64 = 0;
+ *lds_v16f64 = 0;
+}
+
+// CHECK-LABEL: @private_memory_alignment_alloca(
+// CHECK: %private_i8 = alloca [4 x i8], align 1
+// CHECK: %private_v2i8 = alloca [4 x <2 x i8>], align 2
+// CHECK: %private_v3i8 = alloca [4 x <3 x i8>], align 4
+// CHECK: %private_v4i8 = alloca [4 x <4 x i8>], align 4
+// CHECK: %private_v8i8 = alloca [4 x <8 x i8>], align 8
+// CHECK: %private_v16i8 = alloca [4 x <16 x i8>], align 16
+// CHECK: %private_i16 = alloca [4 x i16], align 2
+// CHECK: %private_v2i16 = alloca [4 x <2 x i16>], align 4
+// CHECK: %private_v3i16 = alloca [4 x <3 x i16>], align 8
+// CHECK: %private_v4i16 = alloca [4 x <4 x i16>], align 8
+// CHECK: %private_v8i16 = alloca [4 x <8 x i16>], align 16
+// CHECK: %private_v16i16 = alloca [4 x <16 x i16>], align 32
+// CHECK: %private_i32 = alloca [4 x i32], align 4
+// CHECK: %private_v2i32 = alloca [4 x <2 x i32>], align 8
+// CHECK: %private_v3i32 = alloca [4 x <3 x i32>], align 16
+// CHECK: %private_v4i32 = alloca [4 x <4 x i32>], align 16
+// CHECK: %private_v8i32 = alloca [4 x <8 x i32>], align 32
+// CHECK: %private_v16i32 = alloca [4 x <16 x i32>], align 64
+// CHECK: %private_i64 = alloca [4 x i64], align 8
+// CHECK: %private_v2i64 = alloca [4 x <2 x i64>], align 16
+// CHECK: %private_v3i64 = alloca [4 x <3 x i64>], align 32
+// CHECK: %private_v4i64 = alloca [4 x <4 x i64>], align 32
+// CHECK: %private_v8i64 = alloca [4 x <8 x i64>], align 64
+// CHECK: %private_v16i64 = alloca [4 x <16 x i64>], align 128
+// CHECK: %private_f16 = alloca [4 x half], align 2
+// CHECK: %private_v2f16 = alloca [4 x <2 x half>], align 4
+// CHECK: %private_v3f16 = alloca [4 x <3 x half>], align 8
+// CHECK: %private_v4f16 = alloca [4 x <4 x half>], align 8
+// CHECK: %private_v8f16 = alloca [4 x <8 x half>], align 16
+// CHECK: %private_v16f16 = alloca [4 x <16 x half>], align 32
+// CHECK: %private_f32 = alloca [4 x float], align 4
+// CHECK: %private_v2f32 = alloca [4 x <2 x float>], align 8
+// CHECK: %private_v3f32 = alloca [4 x <3 x float>], align 16
+// CHECK: %private_v4f32 = alloca [4 x <4 x float>], align 16
+// CHECK: %private_v8f32 = alloca [4 x <8 x float>], align 32
+// CHECK: %private_v16f32 = alloca [4 x <16 x float>], align 64
+// CHECK: %private_f64 = alloca [4 x double], align 8
+// CHECK: %private_v2f64 = alloca [4 x <2 x double>], align 16
+// CHECK: %private_v3f64 = alloca [4 x <3 x double>], align 32
+// CHECK: %private_v4f64 = alloca [4 x <4 x double>], align 32
+// CHECK: %private_v8f64 = alloca [4 x <8 x double>], align 64
+// CHECK: %private_v16f64 = alloca [4 x <16 x double>], align 128
+
+// CHECK: store volatile i8 0, i8* %arraydecay, align 1
+// CHECK: store volatile <2 x i8> zeroinitializer, <2 x i8>* %arraydecay{{[0-9]+}}, align 2
+// CHECK: store volatile <4 x i8> <i8 0, i8 0, i8 0, i8 undef>, <4 x i8>* %storetmp, align 4
+// CHECK: store volatile <4 x i8> zeroinitializer, <4 x i8>* %arraydecay{{[0-9]+}}, align 4
+// CHECK: store volatile <8 x i8> zeroinitializer, <8 x i8>* %arraydecay{{[0-9]+}}, align 8
+// CHECK: store volatile <16 x i8> zeroinitializer, <16 x i8>* %arraydecay{{[0-9]+}}, align 16
+// CHECK: store volatile i16 0, i16* %arraydecay{{[0-9]+}}, align 2
+// CHECK: store volatile <2 x i16> zeroinitializer, <2 x i16>* %arraydecay{{[0-9]+}}, align 4
+// CHECK: store volatile <4 x i16> <i16 0, i16 0, i16 0, i16 undef>, <4 x i16>* %storetmp{{[0-9]+}}, align 8
+// CHECK: store volatile <4 x i16> zeroinitializer, <4 x i16>* %arraydecay{{[0-9]+}}, align 8
+// CHECK: store volatile <8 x i16> zeroinitializer, <8 x i16>* %arraydecay{{[0-9]+}}, align 16
+// CHECK: store volatile <16 x i16> zeroinitializer, <16 x i16>* %arraydecay{{[0-9]+}}, align 32
+// CHECK: store volatile i32 0, i32* %arraydecay{{[0-9]+}}, align 4
+// CHECK: store volatile <2 x i32> zeroinitializer, <2 x i32>* %arraydecay{{[0-9]+}}, align 8
+// CHECK: store volatile <4 x i32> <i32 0, i32 0, i32 0, i32 undef>, <4 x i32>* %storetmp16, align 16
+// CHECK: store volatile <4 x i32> zeroinitializer, <4 x i32>* %arraydecay{{[0-9]+}}, align 16
+// CHECK: store volatile <8 x i32> zeroinitializer, <8 x i32>* %arraydecay{{[0-9]+}}, align 32
+// CHECK: store volatile <16 x i32> zeroinitializer, <16 x i32>* %arraydecay{{[0-9]+}}, align 64
+// CHECK: store volatile i64 0, i64* %arraydecay{{[0-9]+}}, align 8
+// CHECK: store volatile <2 x i64> zeroinitializer, <2 x i64>* %arraydecay{{[0-9]+}}, align 16
+// CHECK: store volatile <4 x i64> <i64 0, i64 0, i64 0, i64 undef>, <4 x i64>* %storetmp23, align 32
+// CHECK: store volatile <4 x i64> zeroinitializer, <4 x i64>* %arraydecay{{[0-9]+}}, align 32
+// CHECK: store volatile <8 x i64> zeroinitializer, <8 x i64>* %arraydecay{{[0-9]+}}, align 64
+// CHECK: store volatile <16 x i64> zeroinitializer, <16 x i64>* %arraydecay{{[0-9]+}}, align 128
+// CHECK: store volatile half 0xH0000, half* %arraydecay{{[0-9]+}}, align 2
+// CHECK: store volatile <2 x half> zeroinitializer, <2 x half>* %arraydecay{{[0-9]+}}, align 4
+// CHECK: store volatile <4 x half> <half 0xH0000, half 0xH0000, half 0xH0000, half undef>, <4 x half>* %storetmp{{[0-9]+}}, align 8
+// CHECK: store volatile <4 x half> zeroinitializer, <4 x half>* %arraydecay{{[0-9]+}}, align 8
+// CHECK: store volatile <8 x half> zeroinitializer, <8 x half>* %arraydecay{{[0-9]+}}, align 16
+// CHECK: store volatile <16 x half> zeroinitializer, <16 x half>* %arraydecay{{[0-9]+}}, align 32
+// CHECK: store volatile float 0.000000e+00, float* %arraydecay34, align 4
+// CHECK: store volatile <2 x float> zeroinitializer, <2 x float>* %arraydecay{{[0-9]+}}, align 8
+// CHECK: store volatile <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float undef>, <4 x float>* %storetmp{{[0-9]+}}, align 16
+// CHECK: store volatile <4 x float> zeroinitializer, <4 x float>* %arraydecay{{[0-9]+}}, align 16
+// CHECK: store volatile <8 x float> zeroinitializer, <8 x float>* %arraydecay{{[0-9]+}}, align 32
+// CHECK: store volatile <16 x float> zeroinitializer, <16 x float>* %arraydecay{{[0-9]+}}, align 64
+// CHECK: store volatile double 0.000000e+00, double* %arraydecay{{[0-9]+}}, align 8
+// CHECK: store volatile <2 x double> zeroinitializer, <2 x double>* %arraydecay{{[0-9]+}}, align 16
+// CHECK: store volatile <4 x double> <double 0.000000e+00, double 0.000000e+00, double 0.000000e+00, double undef>, <4 x double>* %storetmp{{[0-9]+}}, align 32
+// CHECK: store volatile <4 x double> zeroinitializer, <4 x double>* %arraydecay{{[0-9]+}}, align 32
+// CHECK: store volatile <8 x double> zeroinitializer, <8 x double>* %arraydecay{{[0-9]+}}, align 64
+// CHECK: store volatile <16 x double> zeroinitializer, <16 x double>* %arraydecay{{[0-9]+}}, align 128
+kernel void private_memory_alignment_alloca()
+{
+ volatile private char private_i8[4];
+ volatile private char2 private_v2i8[4];
+ volatile private char3 private_v3i8[4];
+ volatile private char4 private_v4i8[4];
+ volatile private char8 private_v8i8[4];
+ volatile private char16 private_v16i8[4];
+
+ volatile private short private_i16[4];
+ volatile private short2 private_v2i16[4];
+ volatile private short3 private_v3i16[4];
+ volatile private short4 private_v4i16[4];
+ volatile private short8 private_v8i16[4];
+ volatile private short16 private_v16i16[4];
+
+ volatile private int private_i32[4];
+ volatile private int2 private_v2i32[4];
+ volatile private int3 private_v3i32[4];
+ volatile private int4 private_v4i32[4];
+ volatile private int8 private_v8i32[4];
+ volatile private int16 private_v16i32[4];
+
+ volatile private long private_i64[4];
+ volatile private long2 private_v2i64[4];
+ volatile private long3 private_v3i64[4];
+ volatile private long4 private_v4i64[4];
+ volatile private long8 private_v8i64[4];
+ volatile private long16 private_v16i64[4];
+
+ volatile private half private_f16[4];
+ volatile private half2 private_v2f16[4];
+ volatile private half3 private_v3f16[4];
+ volatile private half4 private_v4f16[4];
+ volatile private half8 private_v8f16[4];
+ volatile private half16 private_v16f16[4];
+
+ volatile private float private_f32[4];
+ volatile private float2 private_v2f32[4];
+ volatile private float3 private_v3f32[4];
+ volatile private float4 private_v4f32[4];
+ volatile private float8 private_v8f32[4];
+ volatile private float16 private_v16f32[4];
+
+ volatile private double private_f64[4];
+ volatile private double2 private_v2f64[4];
+ volatile private double3 private_v3f64[4];
+ volatile private double4 private_v4f64[4];
+ volatile private double8 private_v8f64[4];
+ volatile private double16 private_v16f64[4];
+
+ *private_i8 = 0;
+ *private_v2i8 = 0;
+ *private_v3i8 = 0;
+ *private_v4i8 = 0;
+ *private_v8i8 = 0;
+ *private_v16i8 = 0;
+
+ *private_i16 = 0;
+ *private_v2i16 = 0;
+ *private_v3i16 = 0;
+ *private_v4i16 = 0;
+ *private_v8i16 = 0;
+ *private_v16i16 = 0;
+
+ *private_i32 = 0;
+ *private_v2i32 = 0;
+ *private_v3i32 = 0;
+ *private_v4i32 = 0;
+ *private_v8i32 = 0;
+ *private_v16i32 = 0;
+
+ *private_i64 = 0;
+ *private_v2i64 = 0;
+ *private_v3i64 = 0;
+ *private_v4i64 = 0;
+ *private_v8i64 = 0;
+ *private_v16i64 = 0;
+
+ *private_f16 = 0;
+ *private_v2f16 = 0;
+ *private_v3f16 = 0;
+ *private_v4f16 = 0;
+ *private_v8f16 = 0;
+ *private_v16f16 = 0;
+
+ *private_f32 = 0;
+ *private_v2f32 = 0;
+ *private_v3f32 = 0;
+ *private_v4f32 = 0;
+ *private_v8f32 = 0;
+ *private_v16f32 = 0;
+
+ *private_f64 = 0;
+ *private_v2f64 = 0;
+ *private_v3f64 = 0;
+ *private_v4f64 = 0;
+ *private_v8f64 = 0;
+ *private_v16f64 = 0;
+}
diff --git a/test/CodeGenOpenCL/amdgpu-attrs.cl b/test/CodeGenOpenCL/amdgpu-attrs.cl
index 4ca85d316104..c914f2e6514f 100644
--- a/test/CodeGenOpenCL/amdgpu-attrs.cl
+++ b/test/CodeGenOpenCL/amdgpu-attrs.cl
@@ -129,6 +129,16 @@ kernel void flat_work_group_size_32_64_waves_per_eu_2_4_num_sgpr_32_num_vgpr_64(
// CHECK: define amdgpu_kernel void @flat_work_group_size_32_64_waves_per_eu_2_4_num_sgpr_32_num_vgpr_64() [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32_NUM_VGPR_64:#[0-9]+]]
}
+__attribute__((reqd_work_group_size(32, 2, 1))) // expected-no-diagnostics
+kernel void reqd_work_group_size_32_2_1() {
+// CHECK: define amdgpu_kernel void @reqd_work_group_size_32_2_1() [[FLAT_WORK_GROUP_SIZE_64_64:#[0-9]+]]
+}
+__attribute__((reqd_work_group_size(32, 2, 1), amdgpu_flat_work_group_size(16, 128))) // expected-no-diagnostics
+kernel void reqd_work_group_size_32_2_1_flat_work_group_size_16_128() {
+// CHECK: define amdgpu_kernel void @reqd_work_group_size_32_2_1_flat_work_group_size_16_128() [[FLAT_WORK_GROUP_SIZE_16_128:#[0-9]+]]
+}
+
+
// Make sure this is silently accepted on other targets.
// X86-NOT: "amdgpu-flat-work-group-size"
// X86-NOT: "amdgpu-waves-per-eu"
@@ -142,6 +152,8 @@ kernel void flat_work_group_size_32_64_waves_per_eu_2_4_num_sgpr_32_num_vgpr_64(
// CHECK-NOT: "amdgpu-num-vgpr"="0"
// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_64_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="64,64"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_16_128]] = { noinline nounwind "amdgpu-flat-work-group-size"="16,128"
// CHECK-DAG: attributes [[WAVES_PER_EU_2]] = { noinline nounwind "amdgpu-waves-per-eu"="2"
// CHECK-DAG: attributes [[WAVES_PER_EU_2_4]] = { noinline nounwind "amdgpu-waves-per-eu"="2,4"
// CHECK-DAG: attributes [[NUM_SGPR_32]] = { noinline nounwind "amdgpu-num-sgpr"="32"
diff --git a/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl b/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
new file mode 100644
index 000000000000..c0b30095a679
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
@@ -0,0 +1,125 @@
+// RUN: %clang -cl-std=CL2.0 -emit-llvm -g -O0 -S -target amdgcn-amd-amdhsa -mcpu=fiji -o - %s | FileCheck %s
+
+// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_NONE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}})
+// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_LOCAL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}}, dwarfAddressSpace: 2)
+// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_PRIVATE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}}, dwarfAddressSpace: 1)
+
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar0", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+global int *FileVar0;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+constant int *FileVar1;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: false, isDefinition: true)
+local int *FileVar2;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar3", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: false, isDefinition: true)
+private int *FileVar3;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar4", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+int *FileVar4;
+
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+global int *global FileVar5;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+constant int *global FileVar6;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: false, isDefinition: true)
+local int *global FileVar7;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: false, isDefinition: true)
+private int *global FileVar8;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+int *global FileVar9;
+
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar10", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+global int *constant FileVar10 = 0;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar11", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+constant int *constant FileVar11 = 0;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar12", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: false, isDefinition: true)
+local int *constant FileVar12 = 0;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar13", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: false, isDefinition: true)
+private int *constant FileVar13 = 0;
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar14", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+int *constant FileVar14 = 0;
+
+kernel void kernel1(
+ // CHECK-DAG: !DILocalVariable(name: "KernelArg0", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ global int *KernelArg0,
+ // CHECK-DAG: !DILocalVariable(name: "KernelArg1", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ constant int *KernelArg1,
+ // CHECK-DAG: !DILocalVariable(name: "KernelArg2", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]])
+ local int *KernelArg2) {
+ private int *Tmp0;
+ int *Tmp1;
+
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar0", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ global int *FuncVar0 = KernelArg0;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ constant int *FuncVar1 = KernelArg1;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]])
+ local int *FuncVar2 = KernelArg2;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar3", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]])
+ private int *FuncVar3 = Tmp0;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar4", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ int *FuncVar4 = Tmp1;
+
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ global int *constant FuncVar5 = KernelArg0;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ constant int *constant FuncVar6 = KernelArg1;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]])
+ local int *constant FuncVar7 = KernelArg2;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]])
+ private int *constant FuncVar8 = Tmp0;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ int *constant FuncVar9 = Tmp1;
+
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar10", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+ global int *local FuncVar10; FuncVar10 = KernelArg0;
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar11", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+ constant int *local FuncVar11; FuncVar11 = KernelArg1;
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar12", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: true, isDefinition: true)
+ local int *local FuncVar12; FuncVar12 = KernelArg2;
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar13", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: true, isDefinition: true)
+ private int *local FuncVar13; FuncVar13 = Tmp0;
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar14", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+ int *local FuncVar14; FuncVar14 = Tmp1;
+
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar15", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ global int *private FuncVar15 = KernelArg0;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar16", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ constant int *private FuncVar16 = KernelArg1;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar17", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]])
+ local int *private FuncVar17 = KernelArg2;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar18", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]])
+ private int *private FuncVar18 = Tmp0;
+ // CHECK-DAG: !DILocalVariable(name: "FuncVar19", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+ int *private FuncVar19 = Tmp1;
+}
+
+struct FileStruct0 {
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem0", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}})
+ global int *StructMem0;
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}}, offset: {{[0-9]+}})
+ constant int *StructMem1;
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_LOCAL]], size: {{[0-9]+}}, offset: {{[0-9]+}})
+ local int *StructMem2;
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem3", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_PRIVATE]], size: {{[0-9]+}}, offset: {{[0-9]+}})
+ private int *StructMem3;
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem4", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}}, offset: {{[0-9]+}})
+ int *StructMem4;
+};
+
+struct FileStruct1 {
+ union {
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem0", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}})
+ global int *UnionMem0;
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}})
+ constant int *UnionMem1;
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_LOCAL]], size: {{[0-9]+}})
+ local int *UnionMem2;
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem3", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_PRIVATE]], size: {{[0-9]+}})
+ private int *UnionMem3;
+ // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem4", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: ![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}})
+ int *UnionMem4;
+ };
+ long StructMem0;
+};
+
+kernel void kernel2(global struct FileStruct0 *Kernel2Arg0,
+ global struct FileStruct1 *Kernel2Arg1) {}
diff --git a/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl b/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
new file mode 100644
index 000000000000..b02ad46224b0
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
@@ -0,0 +1,131 @@
+// RUN: %clang -cl-std=CL2.0 -emit-llvm -g -O0 -S -target amdgcn-amd-amdhsa -mcpu=fiji -o - %s | FileCheck %s
+
+// CHECK-DAG: ![[NONE:[0-9]+]] = !DIExpression()
+// CHECK-DAG: ![[LOCAL:[0-9]+]] = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef)
+// CHECK-DAG: ![[PRIVATE:[0-9]+]] = !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)
+
+// CHECK-DAG: ![[FILEVAR0:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar0", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR0]])
+global int *FileVar0;
+// CHECK-DAG: ![[FILEVAR1:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR1]])
+constant int *FileVar1;
+// CHECK-DAG: ![[FILEVAR2:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR2]])
+local int *FileVar2;
+// CHECK-DAG: ![[FILEVAR3:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar3", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR3]])
+private int *FileVar3;
+// CHECK-DAG: ![[FILEVAR4:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar4", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR4]])
+int *FileVar4;
+
+// CHECK-DAG: ![[FILEVAR5:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR5]])
+global int *global FileVar5;
+// CHECK-DAG: ![[FILEVAR6:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR6]])
+constant int *global FileVar6;
+// CHECK-DAG: ![[FILEVAR7:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR7]])
+local int *global FileVar7;
+// CHECK-DAG: ![[FILEVAR8:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR8]])
+private int *global FileVar8;
+// CHECK-DAG: ![[FILEVAR9:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR9]])
+int *global FileVar9;
+
+// CHECK-DAG: ![[FILEVAR10:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar10", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR10]])
+global int *constant FileVar10 = 0;
+// CHECK-DAG: ![[FILEVAR11:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar11", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR11]])
+constant int *constant FileVar11 = 0;
+// CHECK-DAG: ![[FILEVAR12:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar12", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR12]])
+local int *constant FileVar12 = 0;
+// CHECK-DAG: ![[FILEVAR13:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar13", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR13]])
+private int *constant FileVar13 = 0;
+// CHECK-DAG: ![[FILEVAR14:[0-9]+]] = distinct !DIGlobalVariable(name: "FileVar14", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: false, isDefinition: true)
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR14]])
+int *constant FileVar14 = 0;
+
+kernel void kernel1(
+ // CHECK-DAG: ![[KERNELARG0:[0-9]+]] = !DILocalVariable(name: "KernelArg0", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[KERNELARG0]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ global int *KernelArg0,
+ // CHECK-DAG: ![[KERNELARG1:[0-9]+]] = !DILocalVariable(name: "KernelArg1", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[KERNELARG1]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ constant int *KernelArg1,
+ // CHECK-DAG: ![[KERNELARG2:[0-9]+]] = !DILocalVariable(name: "KernelArg2", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(3)** {{.*}}, metadata ![[KERNELARG2]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ local int *KernelArg2) {
+ private int *Tmp0;
+ int *Tmp1;
+
+ // CHECK-DAG: ![[FUNCVAR0:[0-9]+]] = !DILocalVariable(name: "FuncVar0", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[FUNCVAR0]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ global int *FuncVar0 = KernelArg0;
+ // CHECK-DAG: ![[FUNCVAR1:[0-9]+]] = !DILocalVariable(name: "FuncVar1", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[FUNCVAR1]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ constant int *FuncVar1 = KernelArg1;
+ // CHECK-DAG: ![[FUNCVAR2:[0-9]+]] = !DILocalVariable(name: "FuncVar2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(3)** {{.*}}, metadata ![[FUNCVAR2]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ local int *FuncVar2 = KernelArg2;
+ // CHECK-DAG: ![[FUNCVAR3:[0-9]+]] = !DILocalVariable(name: "FuncVar3", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32** {{.*}}, metadata ![[FUNCVAR3]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ private int *FuncVar3 = Tmp0;
+ // CHECK-DAG: ![[FUNCVAR4:[0-9]+]] = !DILocalVariable(name: "FuncVar4", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(4)** {{.*}}, metadata ![[FUNCVAR4]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ int *FuncVar4 = Tmp1;
+
+ // CHECK-DAG: ![[FUNCVAR5:[0-9]+]] = !DILocalVariable(name: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[FUNCVAR5]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
+ global int *constant FuncVar5 = KernelArg0;
+ // CHECK-DAG: ![[FUNCVAR6:[0-9]+]] = !DILocalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[FUNCVAR6]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
+ constant int *constant FuncVar6 = KernelArg1;
+ // CHECK-DAG: ![[FUNCVAR7:[0-9]+]] = !DILocalVariable(name: "FuncVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(3)** {{.*}}, metadata ![[FUNCVAR7]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
+ local int *constant FuncVar7 = KernelArg2;
+ // CHECK-DAG: ![[FUNCVAR8:[0-9]+]] = !DILocalVariable(name: "FuncVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32** {{.*}}, metadata ![[FUNCVAR8]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
+ private int *constant FuncVar8 = Tmp0;
+ // CHECK-DAG: ![[FUNCVAR9:[0-9]+]] = !DILocalVariable(name: "FuncVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(4)** {{.*}}, metadata ![[FUNCVAR9]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
+ int *constant FuncVar9 = Tmp1;
+
+ // CHECK-DAG: ![[FUNCVAR10:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar10", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR10]], expr: ![[LOCAL]])
+ global int *local FuncVar10; FuncVar10 = KernelArg0;
+ // CHECK-DAG: ![[FUNCVAR11:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar11", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR11]], expr: ![[LOCAL]])
+ constant int *local FuncVar11; FuncVar11 = KernelArg1;
+ // CHECK-DAG: ![[FUNCVAR12:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar12", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR12]], expr: ![[LOCAL]])
+ local int *local FuncVar12; FuncVar12 = KernelArg2;
+ // CHECK-DAG: ![[FUNCVAR13:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar13", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR13]], expr: ![[LOCAL]])
+ private int *local FuncVar13; FuncVar13 = Tmp0;
+ // CHECK-DAG: ![[FUNCVAR14:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar14", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR14]], expr: ![[LOCAL]])
+ int *local FuncVar14; FuncVar14 = Tmp1;
+
+ // CHECK-DAG: ![[FUNCVAR15:[0-9]+]] = !DILocalVariable(name: "FuncVar15", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[FUNCVAR15]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ global int *private FuncVar15 = KernelArg0;
+ // CHECK-DAG: ![[FUNCVAR16:[0-9]+]] = !DILocalVariable(name: "FuncVar16", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[FUNCVAR16]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ constant int *private FuncVar16 = KernelArg1;
+ // CHECK-DAG: ![[FUNCVAR17:[0-9]+]] = !DILocalVariable(name: "FuncVar17", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(3)** {{.*}}, metadata ![[FUNCVAR17]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ local int *private FuncVar17 = KernelArg2;
+ // CHECK-DAG: ![[FUNCVAR18:[0-9]+]] = !DILocalVariable(name: "FuncVar18", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32** {{.*}}, metadata ![[FUNCVAR18]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ private int *private FuncVar18 = Tmp0;
+ // CHECK-DAG: ![[FUNCVAR19:[0-9]+]] = !DILocalVariable(name: "FuncVar19", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(4)** {{.*}}, metadata ![[FUNCVAR19]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
+ int *private FuncVar19 = Tmp1;
+}
diff --git a/test/CodeGenOpenCL/amdgpu-env-amdgiz.cl b/test/CodeGenOpenCL/amdgpu-env-amdgiz.cl
new file mode 100644
index 000000000000..4cb8d95fa098
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgpu-env-amdgiz.cl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -O0 -triple amdgcn -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -O0 -triple amdgcn---opencl -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -O0 -triple amdgcn---amdgiz -emit-llvm -o - | FileCheck -check-prefix=GIZ %s
+// RUN: %clang_cc1 %s -O0 -triple amdgcn---amdgizcl -emit-llvm -o - | FileCheck -check-prefix=GIZ %s
+
+// CHECK: target datalayout = "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"
+// GIZ: target datalayout = "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"
+void foo(void) {}
+
diff --git a/test/CodeGenOpenCL/amdgpu-nullptr.cl b/test/CodeGenOpenCL/amdgpu-nullptr.cl
index 2d36fa90a6ab..37c7469aa180 100644
--- a/test/CodeGenOpenCL/amdgpu-nullptr.cl
+++ b/test/CodeGenOpenCL/amdgpu-nullptr.cl
@@ -20,7 +20,7 @@ typedef struct {
// Test 0 as initializer.
-// CHECK: @private_p = local_unnamed_addr addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4
+// CHECK: @private_p = local_unnamed_addr addrspace(1) global i8* null, align 4
private char *private_p = 0;
// CHECK: @local_p = local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4
@@ -37,7 +37,7 @@ generic char *generic_p = 0;
// Test NULL as initializer.
-// CHECK: @private_p_NULL = local_unnamed_addr addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4
+// CHECK: @private_p_NULL = local_unnamed_addr addrspace(1) global i8* null, align 4
private char *private_p_NULL = NULL;
// CHECK: @local_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4
@@ -58,38 +58,55 @@ generic char *generic_p_NULL = NULL;
// CHECK: @fold_generic = local_unnamed_addr addrspace(1) global i32 addrspace(4)* null, align 4
generic int *fold_generic = (global int*)(generic float*)(private char*)0;
-// CHECK: @fold_priv = local_unnamed_addr addrspace(1) global i16* addrspacecast (i16 addrspace(4)* null to i16*), align 4
+// CHECK: @fold_priv = local_unnamed_addr addrspace(1) global i16* null, align 4
private short *fold_priv = (private short*)(generic int*)(global void*)0;
-// CHECK: @fold_priv_arith = local_unnamed_addr addrspace(1) global i8* inttoptr (i32 9 to i8*), align 4
+// CHECK: @fold_priv_arith = local_unnamed_addr addrspace(1) global i8* inttoptr (i32 10 to i8*), align 4
private char *fold_priv_arith = (private char*)0 + 10;
-// CHECK: @fold_int = local_unnamed_addr addrspace(1) global i32 13, align 4
+// CHECK: @fold_int = local_unnamed_addr addrspace(1) global i32 14, align 4
int fold_int = (int)(private void*)(generic char*)(global int*)0 + 14;
-// CHECK: @fold_int2 = local_unnamed_addr addrspace(1) global i32 12, align 4
+// CHECK: @fold_int2 = local_unnamed_addr addrspace(1) global i32 13, align 4
int fold_int2 = (int) ((private void*)0 + 13);
-// CHECK: @fold_int3 = local_unnamed_addr addrspace(1) global i32 -1, align 4
+// CHECK: @fold_int3 = local_unnamed_addr addrspace(1) global i32 0, align 4
int fold_int3 = (int) ((private int*)0);
-// CHECK: @fold_int4 = local_unnamed_addr addrspace(1) global i32 7, align 4
+// CHECK: @fold_int4 = local_unnamed_addr addrspace(1) global i32 8, align 4
int fold_int4 = (int) &((private int*)0)[2];
-// CHECK: @fold_int5 = local_unnamed_addr addrspace(1) global i32 3, align 4
+// CHECK: @fold_int5 = local_unnamed_addr addrspace(1) global i32 4, align 4
int fold_int5 = (int) &((private StructTy1*)0)->p2;
+
+// CHECK: @fold_int_local = local_unnamed_addr addrspace(1) global i32 13, align 4
+int fold_int_local = (int)(local void*)(generic char*)(global int*)0 + 14;
+
+// CHECK: @fold_int2_local = local_unnamed_addr addrspace(1) global i32 12, align 4
+int fold_int2_local = (int) ((local void*)0 + 13);
+
+// CHECK: @fold_int3_local = local_unnamed_addr addrspace(1) global i32 -1, align 4
+int fold_int3_local = (int) ((local int*)0);
+
+// CHECK: @fold_int4_local = local_unnamed_addr addrspace(1) global i32 7, align 4
+int fold_int4_local = (int) &((local int*)0)[2];
+
+// CHECK: @fold_int5_local = local_unnamed_addr addrspace(1) global i32 3, align 4
+int fold_int5_local = (int) &((local StructTy1*)0)->p2;
+
+
// Test static variable initialization.
-// NOOPT: @test_static_var.sp1 = internal addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4
-// NOOPT: @test_static_var.sp2 = internal addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4
-// NOOPT: @test_static_var.sp3 = internal addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4
-// NOOPT: @test_static_var.sp4 = internal addrspace(1) global i8* null, align 4
-// NOOPT: @test_static_var.sp5 = internal addrspace(1) global i8* null, align 4
-// NOOPT: @test_static_var.SS1 = internal addrspace(1) global %struct.StructTy1 { i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4
-// NOOPT: @test_static_var.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 4
+// NOOPT: @test_static_var_private.sp1 = internal addrspace(1) global i8* null, align 4
+// NOOPT: @test_static_var_private.sp2 = internal addrspace(1) global i8* null, align 4
+// NOOPT: @test_static_var_private.sp3 = internal addrspace(1) global i8* null, align 4
+// NOOPT: @test_static_var_private.sp4 = internal addrspace(1) global i8* null, align 4
+// NOOPT: @test_static_var_private.sp5 = internal addrspace(1) global i8* null, align 4
+// NOOPT: @test_static_var_private.SS1 = internal addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4
+// NOOPT: @test_static_var_private.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 4
-void test_static_var(void) {
+void test_static_var_private(void) {
static private char *sp1 = 0;
static private char *sp2 = NULL;
static private char *sp3;
@@ -100,18 +117,35 @@ void test_static_var(void) {
static StructTy2 SS2;
}
+// NOOPT: @test_static_var_local.sp1 = internal addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4
+// NOOPT: @test_static_var_local.sp2 = internal addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4
+// NOOPT: @test_static_var_local.sp3 = internal addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4
+// NOOPT: @test_static_var_local.sp4 = internal addrspace(1) global i8 addrspace(3)* null, align 4
+// NOOPT: @test_static_var_local.sp5 = internal addrspace(1) global i8 addrspace(3)* null, align 4
+// NOOPT: @test_static_var_local.SS1 = internal addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4
+// NOOPT: @test_static_var_local.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 4
+void test_static_var_local(void) {
+ static local char *sp1 = 0;
+ static local char *sp2 = NULL;
+ static local char *sp3;
+ static local char *sp4 = (local char*)((void)0, 0);
+ const int x = 0;
+ static local char *sp5 = (local char*)x;
+ static StructTy1 SS1;
+ static StructTy2 SS2;
+}
+
// Test function-scope variable initialization.
-// NOOPT-LABEL: test_func_scope_var
-// NOOPT: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8** %sp1, align 4
-// NOOPT: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8** %sp2, align 4
+// NOOPT-LABEL: @test_func_scope_var_private(
+// NOOPT: store i8* null, i8** %sp1, align 4
+// NOOPT: store i8* null, i8** %sp2, align 4
// NOOPT: store i8* null, i8** %sp3, align 4
// NOOPT: store i8* null, i8** %sp4, align 4
// NOOPT: %[[SS1:.*]] = bitcast %struct.StructTy1* %SS1 to i8*
-// NOOPT: call void @llvm.memcpy.p0i8.p2i8.i64(i8* %[[SS1]], i8 addrspace(2)* bitcast (%struct.StructTy1 addrspace(2)* @test_func_scope_var.SS1 to i8 addrspace(2)*), i64 32, i32 4, i1 false)
+// NOOPT: call void @llvm.memcpy.p0i8.p2i8.i64(i8* %[[SS1]], i8 addrspace(2)* bitcast (%struct.StructTy1 addrspace(2)* @test_func_scope_var_private.SS1 to i8 addrspace(2)*), i64 32, i32 4, i1 false)
// NOOPT: %[[SS2:.*]] = bitcast %struct.StructTy2* %SS2 to i8*
// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 4, i1 false)
-
-void test_func_scope_var(void) {
+void test_func_scope_var_private(void) {
private char *sp1 = 0;
private char *sp2 = NULL;
private char *sp3 = (private char*)((void)0, 0);
@@ -121,13 +155,34 @@ void test_func_scope_var(void) {
StructTy2 SS2 = {0, 0, 0};
}
+// Test function-scope variable initialization.
+// NOOPT-LABEL: @test_func_scope_var_local(
+// NOOPT: store i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(3)** %sp1, align 4
+// NOOPT: store i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(3)** %sp2, align 4
+// NOOPT: store i8 addrspace(3)* null, i8 addrspace(3)** %sp3, align 4
+// NOOPT: store i8 addrspace(3)* null, i8 addrspace(3)** %sp4, align 4
+// NOOPT: %[[SS1:.*]] = bitcast %struct.StructTy1* %SS1 to i8*
+// NOOPT: call void @llvm.memcpy.p0i8.p2i8.i64(i8* %[[SS1]], i8 addrspace(2)* bitcast (%struct.StructTy1 addrspace(2)* @test_func_scope_var_local.SS1 to i8 addrspace(2)*), i64 32, i32 4, i1 false)
+// NOOPT: %[[SS2:.*]] = bitcast %struct.StructTy2* %SS2 to i8*
+// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 4, i1 false)
+void test_func_scope_var_local(void) {
+ local char *sp1 = 0;
+ local char *sp2 = NULL;
+ local char *sp3 = (local char*)((void)0, 0);
+ const int x = 0;
+ local char *sp4 = (local char*)x;
+ StructTy1 SS1 = {0, 0, 0, 0, 0};
+ StructTy2 SS2 = {0, 0, 0};
+}
+
+
// Test default initialization of pointers.
// Tentative definition of global variables with non-zero initializer
// cannot have common linkage since common linkage requires zero initialization
// and does not have explicit section.
-// CHECK: @p1 = weak local_unnamed_addr addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4
+// CHECK: @p1 = common local_unnamed_addr addrspace(1) global i8* null, align 4
private char *p1;
// CHECK: @p2 = weak local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4
@@ -144,14 +199,14 @@ generic char *p5;
// Test default initialization of sturcture.
-// CHECK: @S1 = weak local_unnamed_addr addrspace(1) global %struct.StructTy1 { i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4
+// CHECK: @S1 = weak local_unnamed_addr addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4
StructTy1 S1;
// CHECK: @S2 = common local_unnamed_addr addrspace(1) global %struct.StructTy2 zeroinitializer, align 4
StructTy2 S2;
// Test default initialization of array.
-// CHECK: @A1 = weak local_unnamed_addr addrspace(1) global [2 x %struct.StructTy1] [%struct.StructTy1 { i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, %struct.StructTy1 { i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }], align 4
+// CHECK: @A1 = weak local_unnamed_addr addrspace(1) global [2 x %struct.StructTy1] [%struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }], align 4
StructTy1 A1[2];
// CHECK: @A2 = common local_unnamed_addr addrspace(1) global [2 x %struct.StructTy2] zeroinitializer, align 4
@@ -160,7 +215,7 @@ StructTy2 A2[2];
// Test comparison with 0.
// CHECK-LABEL: cmp_private
-// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)
+// CHECK: icmp eq i8* %p, null
void cmp_private(private char* p) {
if (p != 0)
*p = 0;
@@ -199,7 +254,7 @@ void cmp_generic(generic char* p) {
// Test comparison with NULL.
// CHECK-LABEL: cmp_NULL_private
-// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)
+// CHECK: icmp eq i8* %p, null
void cmp_NULL_private(private char* p) {
if (p != NULL)
*p = 0;
@@ -237,7 +292,7 @@ void cmp_NULL_generic(generic char* p) {
// Test storage 0 as null pointer.
// CHECK-LABEL: test_storage_null_pointer
-// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8* addrspace(4)* %arg_private
+// CHECK: store i8* null, i8* addrspace(4)* %arg_private
// CHECK: store i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(3)* addrspace(4)* %arg_local
// CHECK: store i8 addrspace(1)* null, i8 addrspace(1)* addrspace(4)* %arg_global
// CHECK: store i8 addrspace(2)* null, i8 addrspace(2)* addrspace(4)* %arg_constant
@@ -256,7 +311,7 @@ void test_storage_null_pointer(private char** arg_private,
// Test storage NULL as null pointer.
// CHECK-LABEL: test_storage_null_pointer_NULL
-// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8* addrspace(4)* %arg_private
+// CHECK: store i8* null, i8* addrspace(4)* %arg_private
// CHECK: store i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(3)* addrspace(4)* %arg_local
// CHECK: store i8 addrspace(1)* null, i8 addrspace(1)* addrspace(4)* %arg_global
// CHECK: store i8 addrspace(2)* null, i8 addrspace(2)* addrspace(4)* %arg_constant
@@ -281,8 +336,8 @@ void test_pass_null_pointer_arg_calee(private char* arg_private,
generic char* arg_generic);
// CHECK-LABEL: test_pass_null_pointer_arg
-// CHECK: call void @test_pass_null_pointer_arg_calee(i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(1)* null, i8 addrspace(2)* null, i8 addrspace(4)* null)
-// CHECK: call void @test_pass_null_pointer_arg_calee(i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(1)* null, i8 addrspace(2)* null, i8 addrspace(4)* null)
+// CHECK: call void @test_pass_null_pointer_arg_calee(i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(1)* null, i8 addrspace(2)* null, i8 addrspace(4)* null)
+// CHECK: call void @test_pass_null_pointer_arg_calee(i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(1)* null, i8 addrspace(2)* null, i8 addrspace(4)* null)
void test_pass_null_pointer_arg(void) {
test_pass_null_pointer_arg_calee(0, 0, 0, 0, 0);
test_pass_null_pointer_arg_calee(NULL, NULL, NULL, NULL, NULL);
@@ -296,8 +351,8 @@ void test_cast_null_pointer_to_sizet_calee(size_t arg_private,
size_t arg_generic);
// CHECK-LABEL: test_cast_null_pointer_to_sizet
-// CHECK: call void @test_cast_null_pointer_to_sizet_calee(i64 ptrtoint (i8* addrspacecast (i8 addrspace(4)* null to i8*) to i64), i64 ptrtoint (i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*) to i64), i64 0, i64 0, i64 0)
-// CHECK: call void @test_cast_null_pointer_to_sizet_calee(i64 ptrtoint (i8* addrspacecast (i8 addrspace(4)* null to i8*) to i64), i64 ptrtoint (i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*) to i64), i64 0, i64 0, i64 0)
+// CHECK: call void @test_cast_null_pointer_to_sizet_calee(i64 0, i64 ptrtoint (i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*) to i64), i64 0, i64 0, i64 0)
+// CHECK: call void @test_cast_null_pointer_to_sizet_calee(i64 0, i64 ptrtoint (i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*) to i64), i64 0, i64 0, i64 0)
void test_cast_null_pointer_to_sizet(void) {
test_cast_null_pointer_to_sizet_calee((size_t)((private char*)0),
(size_t)((local char*)0),
@@ -409,7 +464,7 @@ TEST_EQ00(constant, constant)
// Test cast to bool.
// CHECK-LABEL: cast_bool_private
-// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)
+// CHECK: icmp eq i8* %p, null
void cast_bool_private(private char* p) {
if (p)
*p = 0;
@@ -453,10 +508,9 @@ typedef struct {
private char *p;
} StructTy3;
-// CHECK-LABEL: test_memset
-// CHECK: call void @llvm.memset.p0i8.i64(i8* {{.*}}, i8 0, i64 32, i32 8, i1 false)
-// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8** {{.*}}
-StructTy3 test_memset(void) {
+// CHECK-LABEL: test_memset_private
+// CHECK: call void @llvm.memset.p0i8.i64(i8* nonnull {{.*}}, i8 0, i64 40, i32 8, i1 false)
+StructTy3 test_memset_private(void) {
StructTy3 S3 = {0, 0, 0, 0, 0};
return S3;
}
@@ -464,22 +518,34 @@ StructTy3 test_memset(void) {
// Test casting literal 0 to pointer.
// A 0 literal casted to pointer should become a null pointer.
-// CHECK-LABEL: test_cast_0_to_ptr
-// CHECK: ret i32* addrspacecast (i32 addrspace(4)* null to i32*)
-private int* test_cast_0_to_ptr(void) {
+// CHECK-LABEL: test_cast_0_to_local_ptr
+// CHECK: ret i32 addrspace(3)* addrspacecast (i32 addrspace(4)* null to i32 addrspace(3)*)
+local int* test_cast_0_to_local_ptr(void) {
+ return (local int*)0;
+}
+
+// CHECK-LABEL: test_cast_0_to_private_ptr
+// CHECK: ret i32* null
+private int* test_cast_0_to_private_ptr(void) {
return (private int*)0;
}
// Test casting non-literal integer with 0 value to pointer.
// A non-literal integer expression with 0 value is casted to a pointer with
-// zero value.
+// zero value.
-// CHECK-LABEL: test_cast_int_to_ptr1
+// CHECK-LABEL: test_cast_int_to_ptr1_private
// CHECK: ret i32* null
-private int* test_cast_int_to_ptr1(void) {
+private int* test_cast_int_to_ptr1_private(void) {
return (private int*)((void)0, 0);
}
+// CHECK-LABEL: test_cast_int_to_ptr1_local
+ // CHECK: ret i32 addrspace(3)* null
+local int* test_cast_int_to_ptr1_local(void) {
+ return (local int*)((void)0, 0);
+}
+
// CHECK-LABEL: test_cast_int_to_ptr2
// CHECK: ret i32* null
private int* test_cast_int_to_ptr2(void) {
@@ -500,15 +566,25 @@ int test_and_nullptr(int a) {
return a && ((private char*)NULL);
}
-// CHECK-LABEL: test_not_ptr
-// CHECK: %[[lnot:.*]] = icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)
+// CHECK-LABEL: test_not_private_ptr
+// CHECK: %[[lnot:.*]] = icmp eq i8* %p, null
+// CHECK: %[[lnot_ext:.*]] = zext i1 %[[lnot]] to i32
+// CHECK: ret i32 %[[lnot_ext]]
+int test_not_private_ptr(private char* p) {
+ return !p;
+}
+
+// CHECK-LABEL: test_not_local_ptr
+// CHECK: %[[lnot:.*]] = icmp eq i8 addrspace(3)* %p, addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*)
// CHECK: %[[lnot_ext:.*]] = zext i1 %[[lnot]] to i32
// CHECK: ret i32 %[[lnot_ext]]
-int test_not_ptr(private char* p) {
+int test_not_local_ptr(local char* p) {
return !p;
}
+
+
// CHECK-LABEL: test_and_ptr
-// CHECK: %[[tobool:.*]] = icmp ne i8* %p1, addrspacecast (i8 addrspace(4)* null to i8*)
+// CHECK: %[[tobool:.*]] = icmp ne i8* %p1, null
// CHECK: %[[tobool1:.*]] = icmp ne i8 addrspace(3)* %p2, addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*)
// CHECK: %[[res:.*]] = and i1 %[[tobool]], %[[tobool1]]
// CHECK: %[[land_ext:.*]] = zext i1 %[[res]] to i32
@@ -518,17 +594,31 @@ int test_and_ptr(private char* p1, local char* p2) {
}
// Test folding of null pointer in function scope.
-// NOOPT-LABEL: test_fold
+// NOOPT-LABEL: test_fold_private
// NOOPT: call void @test_fold_callee
// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 4
// NOOPT: %{{.*}} = sub i64 %{{.*}}, 0
// NOOPT: call void @test_fold_callee
-// NOOPT: %{{.*}} = add nsw i64 %{{.*}}, sext (i32 ptrtoint (i32* addrspacecast (i32 addrspace(4)* null to i32*) to i32) to i64)
+// NOOPT: %{{.*}} = add nsw i64 %{{.*}}, 0
// NOOPT: %{{.*}} = sub nsw i64 %{{.*}}, 1
void test_fold_callee(void);
-void test_fold(void) {
+void test_fold_private(void) {
global int* glob = (test_fold_callee(), (global int*)(generic char*)0);
long x = glob - (global int*)(generic char*)0;
x = x + (int)(test_fold_callee(), (private int*)(generic char*)(global short*)0);
x = x - (int)((private int*)0 == (private int*)(generic char*)0);
}
+
+// NOOPT-LABEL: test_fold_local
+// NOOPT: call void @test_fold_callee
+// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 4
+// NOOPT: %{{.*}} = sub i64 %{{.*}}, 0
+// NOOPT: call void @test_fold_callee
+// NOOPT: %{{.*}} = add nsw i64 %{{.*}}, sext (i32 ptrtoint (i32 addrspace(3)* addrspacecast (i32 addrspace(4)* null to i32 addrspace(3)*) to i32) to i64)
+// NOOPT: %{{.*}} = sub nsw i64 %{{.*}}, 1
+void test_fold_local(void) {
+ global int* glob = (test_fold_callee(), (global int*)(generic char*)0);
+ long x = glob - (global int*)(generic char*)0;
+ x = x + (int)(test_fold_callee(), (local int*)(generic char*)(global short*)0);
+ x = x - (int)((local int*)0 == (local int*)(generic char*)0);
+}
diff --git a/test/CodeGenOpenCL/blocks.cl b/test/CodeGenOpenCL/blocks.cl
new file mode 100644
index 000000000000..5f0cceaf6cdb
--- /dev/null
+++ b/test/CodeGenOpenCL/blocks.cl
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck -check-prefix=GENERIC -check-prefix=COMMON %s
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -O0 -triple amdgcn-amd-amdhsa-opencl | FileCheck -check-prefix=AMD -check-prefix=COMMON %s
+
+// Checking for null instead of @__NSConcreteGlobalBlock symbol
+// COMMON: @__block_literal_global = internal addrspace(1) constant { i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } { i8** null
+void (^block_A)(local void *) = ^(local void *a) {
+ return;
+};
+
+void foo(){
+ int i;
+// Checking for null instead of @_NSConcreteStackBlock symbol
+// COMMON: store i8* null, i8** %block.isa
+ int (^ block_B)(void) = ^{
+ return i;
+ };
+}
diff --git a/test/CodeGenOpenCL/builtins-amdgcn-gfx9.cl b/test/CodeGenOpenCL/builtins-amdgcn-gfx9.cl
new file mode 100644
index 000000000000..333b610f81bd
--- /dev/null
+++ b/test/CodeGenOpenCL/builtins-amdgcn-gfx9.cl
@@ -0,0 +1,11 @@
+// REQUIRES: amdgpu-registered-target
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu gfx900 -S -emit-llvm -o - %s | FileCheck %s
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+// CHECK-LABEL: @test_fmed3_f16
+// CHECK: call half @llvm.amdgcn.fmed3.f16(half %a, half %b, half %c)
+void test_fmed3_f16(global half* out, half a, half b, half c)
+{
+ *out = __builtin_amdgcn_fmed3h(a, b, c);
+}
diff --git a/test/CodeGenOpenCL/builtins-amdgcn-vi.cl b/test/CodeGenOpenCL/builtins-amdgcn-vi.cl
index 0c88fdfb724d..1dad67491832 100644
--- a/test/CodeGenOpenCL/builtins-amdgcn-vi.cl
+++ b/test/CodeGenOpenCL/builtins-amdgcn-vi.cl
@@ -81,3 +81,11 @@ void test_s_memrealtime(global ulong* out)
{
*out = __builtin_amdgcn_s_memrealtime();
}
+
+// CHECK-LABEL: @test_mov_dpp
+// CHECK: call i32 @llvm.amdgcn.mov.dpp.i32(i32 %src, i32 0, i32 0, i32 0, i1 false)
+void test_mov_dpp(global int* out, int src)
+{
+ *out = __builtin_amdgcn_mov_dpp(src, 0, 0, 0, false);
+}
+
diff --git a/test/CodeGenOpenCL/builtins-amdgcn.cl b/test/CodeGenOpenCL/builtins-amdgcn.cl
index ce566b6e876a..a19ce2f1ed59 100644
--- a/test/CodeGenOpenCL/builtins-amdgcn.cl
+++ b/test/CodeGenOpenCL/builtins-amdgcn.cl
@@ -235,6 +235,34 @@ void test_ds_swizzle(global int* out, int a)
*out = __builtin_amdgcn_ds_swizzle(a, 32);
}
+// CHECK-LABEL: @test_ds_permute
+// CHECK: call i32 @llvm.amdgcn.ds.permute(i32 %a, i32 %b)
+void test_ds_permute(global int* out, int a, int b)
+{
+ out[0] = __builtin_amdgcn_ds_permute(a, b);
+}
+
+// CHECK-LABEL: @test_ds_bpermute
+// CHECK: call i32 @llvm.amdgcn.ds.bpermute(i32 %a, i32 %b)
+void test_ds_bpermute(global int* out, int a, int b)
+{
+ *out = __builtin_amdgcn_ds_bpermute(a, b);
+}
+
+// CHECK-LABEL: @test_readfirstlane
+// CHECK: call i32 @llvm.amdgcn.readfirstlane(i32 %a)
+void test_readfirstlane(global int* out, int a)
+{
+ *out = __builtin_amdgcn_readfirstlane(a);
+}
+
+// CHECK-LABEL: @test_readlane
+// CHECK: call i32 @llvm.amdgcn.readlane(i32 %a, i32 %b)
+void test_readlane(global int* out, int a, int b)
+{
+ *out = __builtin_amdgcn_readlane(a, b);
+}
+
// CHECK-LABEL: @test_fcmp_f32
// CHECK: call i64 @llvm.amdgcn.fcmp.f32(float %a, float %b, i32 5)
void test_fcmp_f32(global ulong* out, float a, float b)
@@ -263,6 +291,55 @@ void test_class_f64(global double* out, double a, int b)
*out = __builtin_amdgcn_class(a, b);
}
+// CHECK-LABEL: @test_buffer_wbinvl1
+// CHECK: call void @llvm.amdgcn.buffer.wbinvl1(
+void test_buffer_wbinvl1()
+{
+ __builtin_amdgcn_buffer_wbinvl1();
+}
+
+// CHECK-LABEL: @test_s_dcache_inv
+// CHECK: call void @llvm.amdgcn.s.dcache.inv(
+void test_s_dcache_inv()
+{
+ __builtin_amdgcn_s_dcache_inv();
+}
+
+// CHECK-LABEL: @test_s_waitcnt
+// CHECK: call void @llvm.amdgcn.s.waitcnt(
+void test_s_waitcnt()
+{
+ __builtin_amdgcn_s_waitcnt(0);
+}
+
+// CHECK-LABEL: @test_s_sendmsg
+// CHECK: call void @llvm.amdgcn.s.sendmsg(
+void test_s_sendmsg()
+{
+ __builtin_amdgcn_s_sendmsg(1, 0);
+}
+
+// CHECK-LABEL: @test_s_sendmsg_var
+// CHECK: call void @llvm.amdgcn.s.sendmsg(
+void test_s_sendmsg_var(int in)
+{
+ __builtin_amdgcn_s_sendmsg(1, in);
+}
+
+// CHECK-LABEL: @test_s_sendmsghalt
+// CHECK: call void @llvm.amdgcn.s.sendmsghalt(
+void test_s_sendmsghalt()
+{
+ __builtin_amdgcn_s_sendmsghalt(1, 0);
+}
+
+// CHECK-LABEL: @test_s_sendmsghalt
+// CHECK: call void @llvm.amdgcn.s.sendmsghalt(
+void test_s_sendmsghalt_var(int in)
+{
+ __builtin_amdgcn_s_sendmsghalt(1, in);
+}
+
// CHECK-LABEL: @test_s_barrier
// CHECK: call void @llvm.amdgcn.s.barrier(
void test_s_barrier()
@@ -371,6 +448,17 @@ void test_get_group_id(int d, global int *out)
}
}
+// CHECK-LABEL: @test_s_getreg(
+// CHECK: tail call i32 @llvm.amdgcn.s.getreg(i32 0)
+// CHECK: tail call i32 @llvm.amdgcn.s.getreg(i32 1)
+// CHECK: tail call i32 @llvm.amdgcn.s.getreg(i32 65535)
+void test_s_getreg(volatile global uint *out)
+{
+ *out = __builtin_amdgcn_s_getreg(0);
+ *out = __builtin_amdgcn_s_getreg(1);
+ *out = __builtin_amdgcn_s_getreg(65535);
+}
+
// CHECK-LABEL: @test_get_local_id(
// CHECK: tail call i32 @llvm.amdgcn.workitem.id.x(), !range [[WI_RANGE:![0-9]*]]
// CHECK: tail call i32 @llvm.amdgcn.workitem.id.y(), !range [[WI_RANGE]]
@@ -385,6 +473,13 @@ void test_get_local_id(int d, global int *out)
}
}
+// CHECK-LABEL: @test_fmed3_f32
+// CHECK: call float @llvm.amdgcn.fmed3.f32(
+void test_fmed3_f32(global float* out, float a, float b, float c)
+{
+ *out = __builtin_amdgcn_fmed3f(a, b, c);
+}
+
// CHECK-DAG: [[WI_RANGE]] = !{i32 0, i32 1024}
// CHECK-DAG: attributes #[[NOUNWIND_READONLY:[0-9]+]] = { nounwind readonly }
// CHECK-DAG: attributes #[[READ_EXEC_ATTRS]] = { convergent }
diff --git a/test/CodeGenOpenCL/cl20-device-side-enqueue.cl b/test/CodeGenOpenCL/cl20-device-side-enqueue.cl
index add13b9e3fc4..def290661534 100644
--- a/test/CodeGenOpenCL/cl20-device-side-enqueue.cl
+++ b/test/CodeGenOpenCL/cl20-device-side-enqueue.cl
@@ -2,9 +2,10 @@
// RUN: %clang_cc1 %s -cl-std=CL2.0 -ffake-address-space-map -O0 -emit-llvm -o - -triple "spir64-unknown-unknown" | FileCheck %s --check-prefix=COMMON --check-prefix=B64
typedef void (^bl_t)(local void *);
+typedef struct {int a;} ndrange_t;
// N.B. The check here only exists to set BL_GLOBAL
-// COMMON: @block_G = {{.*}}bitcast ([[BL_GLOBAL:[^@]+@__block_literal_global(\.[0-9]+)?]]
+// COMMON: @block_G = addrspace(1) constant void (i8 addrspace(3)*) addrspace(4)* addrspacecast (void (i8 addrspace(3)*) addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* [[BL_GLOBAL:@__block_literal_global(\.[0-9]+)?]] to void (i8 addrspace(3)*) addrspace(1)*) to void (i8 addrspace(3)*) addrspace(4)*)
const bl_t block_G = (bl_t) ^ (local void *a) {};
kernel void device_side_enqueue(global int *a, global int *b, int i) {
@@ -12,7 +13,7 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
queue_t default_queue;
// COMMON: %flags = alloca i32
unsigned flags = 0;
- // COMMON: %ndrange = alloca %opencl.ndrange_t*
+ // COMMON: %ndrange = alloca %struct.ndrange_t
ndrange_t ndrange;
// COMMON: %clk_event = alloca %opencl.clk_event_t*
clk_event_t clk_event;
@@ -21,12 +22,12 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
// COMMON: %event_wait_list2 = alloca [1 x %opencl.clk_event_t*]
clk_event_t event_wait_list2[] = {clk_event};
+ // COMMON: [[NDR:%[a-z0-9]+]] = alloca %struct.ndrange_t, align 4
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // COMMON: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange
// COMMON: [[BL:%[0-9]+]] = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor addrspace(2)*, i32{{.*}}, i32{{.*}}, i32{{.*}} }>* %block to void ()*
- // COMMON: [[BL_I8:%[0-9]+]] = bitcast void ()* [[BL]] to i8*
- // COMMON: call i32 @__enqueue_kernel_basic(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* [[BL_I8]])
+ // COMMON: [[BL_I8:%[0-9]+]] = addrspacecast void ()* [[BL]] to i8 addrspace(4)*
+ // COMMON: call i32 @__enqueue_kernel_basic(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* byval [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* [[BL_I8]])
enqueue_kernel(default_queue, flags, ndrange,
^(void) {
a[i] = b[i];
@@ -34,12 +35,11 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // COMMON: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange
// COMMON: [[WAIT_EVNT:%[0-9]+]] = addrspacecast %opencl.clk_event_t{{.*}}** %event_wait_list to %opencl.clk_event_t{{.*}}* addrspace(4)*
// COMMON: [[EVNT:%[0-9]+]] = addrspacecast %opencl.clk_event_t{{.*}}** %clk_event to %opencl.clk_event_t{{.*}}* addrspace(4)*
// COMMON: [[BL:%[0-9]+]] = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor addrspace(2)*, i32{{.*}}, i32{{.*}}, i32{{.*}} }>* %block3 to void ()*
- // COMMON: [[BL_I8:%[0-9]+]] = bitcast void ()* [[BL]] to i8*
- // COMMON: call i32 @__enqueue_kernel_basic_events(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}}* addrspace(4)* [[WAIT_EVNT]], %opencl.clk_event_t{{.*}}* addrspace(4)* [[EVNT]], i8* [[BL_I8]])
+ // COMMON: [[BL_I8:%[0-9]+]] = addrspacecast void ()* [[BL]] to i8 addrspace(4)*
+ // COMMON: call i32 @__enqueue_kernel_basic_events(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}}* addrspace(4)* [[WAIT_EVNT]], %opencl.clk_event_t{{.*}}* addrspace(4)* [[EVNT]], i8 addrspace(4)* [[BL_I8]])
enqueue_kernel(default_queue, flags, ndrange, 2, &event_wait_list, &clk_event,
^(void) {
a[i] = b[i];
@@ -47,9 +47,8 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // COMMON: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange
- // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 256)
- // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i64 256)
+ // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i32 256)
+ // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i64 256)
enqueue_kernel(default_queue, flags, ndrange,
^(local void *p) {
return;
@@ -58,11 +57,10 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
char c;
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // COMMON: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange
// B32: [[SIZE:%[0-9]+]] = zext i8 {{%[0-9]+}} to i32
- // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 [[SIZE]])
+ // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i32 [[SIZE]])
// B64: [[SIZE:%[0-9]+]] = zext i8 {{%[0-9]+}} to i64
- // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i64 [[SIZE]])
+ // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i64 [[SIZE]])
enqueue_kernel(default_queue, flags, ndrange,
^(local void *p) {
return;
@@ -71,12 +69,11 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // COMMON: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange
// COMMON: [[AD:%arraydecay[0-9]*]] = getelementptr inbounds [1 x %opencl.clk_event_t*], [1 x %opencl.clk_event_t*]* %event_wait_list2, i32 0, i32 0
// COMMON: [[WAIT_EVNT:%[0-9]+]] = addrspacecast %opencl.clk_event_t{{.*}}** [[AD]] to %opencl.clk_event_t{{.*}}* addrspace(4)*
// COMMON: [[EVNT:%[0-9]+]] = addrspacecast %opencl.clk_event_t{{.*}}** %clk_event to %opencl.clk_event_t{{.*}}* addrspace(4)*
- // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i32, %opencl.clk_event_t{{.*}}* addrspace(4)*, %opencl.clk_event_t{{.*}}* addrspace(4)*, i8*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}} [[WAIT_EVNT]], %opencl.clk_event_t{{.*}} [[EVNT]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 256)
- // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i32, %opencl.clk_event_t{{.*}}* addrspace(4)*, %opencl.clk_event_t{{.*}}* addrspace(4)*, i8*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}} [[WAIT_EVNT]], %opencl.clk_event_t{{.*}} [[EVNT]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i64 256)
+ // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i32, %opencl.clk_event_t{{.*}}* addrspace(4)*, %opencl.clk_event_t{{.*}}* addrspace(4)*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}} [[WAIT_EVNT]], %opencl.clk_event_t{{.*}} [[EVNT]], i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i32 256)
+ // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i32, %opencl.clk_event_t{{.*}}* addrspace(4)*, %opencl.clk_event_t{{.*}}* addrspace(4)*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}} [[WAIT_EVNT]], %opencl.clk_event_t{{.*}} [[EVNT]], i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i64 256)
enqueue_kernel(default_queue, flags, ndrange, 2, event_wait_list2, &clk_event,
^(local void *p) {
return;
@@ -85,14 +82,13 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // COMMON: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange
// COMMON: [[AD:%arraydecay[0-9]*]] = getelementptr inbounds [1 x %opencl.clk_event_t*], [1 x %opencl.clk_event_t*]* %event_wait_list2, i32 0, i32 0
// COMMON: [[WAIT_EVNT:%[0-9]+]] = addrspacecast %opencl.clk_event_t{{.*}}** [[AD]] to %opencl.clk_event_t{{.*}}* addrspace(4)*
// COMMON: [[EVNT:%[0-9]+]] = addrspacecast %opencl.clk_event_t{{.*}}** %clk_event to %opencl.clk_event_t{{.*}}* addrspace(4)*
// B32: [[SIZE:%[0-9]+]] = zext i8 {{%[0-9]+}} to i32
- // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i32, %opencl.clk_event_t{{.*}}* addrspace(4)*, %opencl.clk_event_t{{.*}}* addrspace(4)*, i8*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}}* addrspace(4)* [[WAIT_EVNT]], %opencl.clk_event_t{{.*}}* addrspace(4)* [[EVNT]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 [[SIZE]])
+ // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i32, %opencl.clk_event_t{{.*}}* addrspace(4)*, %opencl.clk_event_t{{.*}}* addrspace(4)*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}}* addrspace(4)* [[WAIT_EVNT]], %opencl.clk_event_t{{.*}}* addrspace(4)* [[EVNT]], i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i32 [[SIZE]])
// B64: [[SIZE:%[0-9]+]] = zext i8 {{%[0-9]+}} to i64
- // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i32, %opencl.clk_event_t{{.*}}* addrspace(4)*, %opencl.clk_event_t{{.*}}* addrspace(4)*, i8*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}}* addrspace(4)* [[WAIT_EVNT]], %opencl.clk_event_t{{.*}}* addrspace(4)* [[EVNT]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i64 [[SIZE]])
+ // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i32, %opencl.clk_event_t{{.*}}* addrspace(4)*, %opencl.clk_event_t{{.*}}* addrspace(4)*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}}* addrspace(4)* [[WAIT_EVNT]], %opencl.clk_event_t{{.*}}* addrspace(4)* [[EVNT]], i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i64 [[SIZE]])
enqueue_kernel(default_queue, flags, ndrange, 2, event_wait_list2, &clk_event,
^(local void *p) {
return;
@@ -102,11 +98,10 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
long l;
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // COMMON: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange
// B32: [[SIZE:%[0-9]+]] = trunc i64 {{%[0-9]+}} to i32
- // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 [[SIZE]])
+ // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i32 [[SIZE]])
// B64: [[SIZE:%[0-9]+]] = load i64, i64* %l
- // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i64 [[SIZE]])
+ // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i64 [[SIZE]])
enqueue_kernel(default_queue, flags, ndrange,
^(local void *p) {
return;
@@ -115,9 +110,8 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t*, %opencl.queue_t** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // COMMON: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange
- // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 0)
- // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i64 4294967296)
+ // B32: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i32 0)
+ // B64: call i32 (%opencl.queue_t{{.*}}*, i32, %struct.ndrange_t*, i8 addrspace(4)*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{(.[0-9]+)?}}, i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* @__block_literal_global{{(.[0-9]+)?}} to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1, i64 4294967296)
enqueue_kernel(default_queue, flags, ndrange,
^(local void *p) {
return;
@@ -126,22 +120,22 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
// The full type of these expressions are long (and repeated elsewhere), so we
// capture it as part of the regex for convenience and clarity.
- // COMMON: store void ()* bitcast ([[BL_A:[^@]+@__block_literal_global.[0-9]+]] to void ()*), void ()** %block_A
+ // COMMON: store void () addrspace(4)* addrspacecast (void () addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* [[BL_A:@__block_literal_global(\.[0-9]+)?]] to void () addrspace(1)*) to void () addrspace(4)*), void () addrspace(4)** %block_A
void (^const block_A)(void) = ^{
return;
};
- // COMMON: store void (i8 addrspace(3)*)* bitcast ([[BL_B:[^@]+@__block_literal_global.[0-9]+]] to void (i8 addrspace(3)*)*), void (i8 addrspace(3)*)** %block_B
+ // COMMON: store void (i8 addrspace(3)*) addrspace(4)* addrspacecast (void (i8 addrspace(3)*) addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* [[BL_B:@__block_literal_global(\.[0-9]+)?]] to void (i8 addrspace(3)*) addrspace(1)*) to void (i8 addrspace(3)*) addrspace(4)*), void (i8 addrspace(3)*) addrspace(4)** %block_B
void (^const block_B)(local void *) = ^(local void *a) {
return;
};
- // COMMON: call i32 @__get_kernel_work_group_size_impl(i8* bitcast ([[BL_A]] to i8*))
+ // COMMON: call i32 @__get_kernel_work_group_size_impl(i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* [[BL_A]] to i8 addrspace(1)*) to i8 addrspace(4)*))
unsigned size = get_kernel_work_group_size(block_A);
- // COMMON: call i32 @__get_kernel_work_group_size_impl(i8* bitcast ([[BL_B]] to i8*))
+ // COMMON: call i32 @__get_kernel_work_group_size_impl(i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* [[BL_B]] to i8 addrspace(1)*) to i8 addrspace(4)*))
size = get_kernel_work_group_size(block_B);
- // COMMON: call i32 @__get_kernel_preferred_work_group_multiple_impl(i8* bitcast ([[BL_A]] to i8*))
+ // COMMON: call i32 @__get_kernel_preferred_work_group_multiple_impl(i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* [[BL_A]] to i8 addrspace(1)*) to i8 addrspace(4)*))
size = get_kernel_preferred_work_group_size_multiple(block_A);
- // COMMON: call i32 @__get_kernel_preferred_work_group_multiple_impl(i8* bitcast ([[BL_GLOBAL]] to i8*))
+ // COMMON: call i32 @__get_kernel_preferred_work_group_multiple_impl(i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(2)* } addrspace(1)* [[BL_GLOBAL]] to i8 addrspace(1)*) to i8 addrspace(4)*))
size = get_kernel_preferred_work_group_size_multiple(block_G);
}
diff --git a/test/CodeGenOpenCL/denorms-are-zero.cl b/test/CodeGenOpenCL/denorms-are-zero.cl
index f398218b4fd7..ca7969ad5f40 100644
--- a/test/CodeGenOpenCL/denorms-are-zero.cl
+++ b/test/CodeGenOpenCL/denorms-are-zero.cl
@@ -1,19 +1,19 @@
// RUN: %clang_cc1 -S -cl-denorms-are-zero -o - %s 2>&1
// RUN: %clang_cc1 -emit-llvm -cl-denorms-are-zero -o - -triple amdgcn--amdhsa -target-cpu fiji %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn--amdhsa -target-cpu fiji %s | FileCheck %s --check-prefix=CHECK-DENORM
-// RUN: %clang_cc1 -emit-llvm -target-feature +fp32-denormals -target-feature -fp64-denormals -cl-denorms-are-zero -o - -triple amdgcn--amdhsa -target-cpu fiji %s | FileCheck --check-prefix=CHECK-FEATURE %s
+// RUN: %clang_cc1 -emit-llvm -target-feature +fp32-denormals -target-feature -fp64-fp16-denormals -cl-denorms-are-zero -o - -triple amdgcn--amdhsa -target-cpu fiji %s | FileCheck --check-prefix=CHECK-FEATURE %s
// For non-amdgcn targets, this test just checks that the -cl-denorms-are-zero argument is accepted
// by clang. This option is currently a no-op, which is allowed by the
// OpenCL specification.
// For amdgcn target cpu fiji, fp32 should be flushed since fiji does not support fp32 denormals, unless +fp32-denormals is
-// explicitly set. amdgcn target always do not flush fp64 denormals.
+// explicitly set. amdgcn target always do not flush fp64 denormals. The control for fp64 and fp16 denormals is the same.
// CHECK-DENORM-LABEL: define void @f()
-// CHECK-DENORM: attributes #{{[0-9]*}} = {{{[^}]*}} "target-features"="{{[^"]*}}+fp64-denormals,{{[^"]*}}-fp32-denormals{{[^"]*}}"
+// CHECK-DENORM: attributes #{{[0-9]*}} = {{{[^}]*}} "target-features"="{{[^"]*}}+fp64-fp16-denormals,{{[^"]*}}-fp32-denormals{{[^"]*}}"
// CHECK-LABEL: define void @f()
-// CHECK: attributes #{{[0-9]*}} = {{{[^}]*}} "target-features"="{{[^"]*}}+fp64-denormals,{{[^"]*}}-fp32-denormals{{[^"]*}}"
+// CHECK: attributes #{{[0-9]*}} = {{{[^}]*}} "target-features"="{{[^"]*}}+fp64-fp16-denormals,{{[^"]*}}-fp32-denormals{{[^"]*}}"
// CHECK-FEATURE-LABEL: define void @f()
-// CHECK-FEATURE: attributes #{{[0-9]*}} = {{{[^}]*}} "target-features"="{{[^"]*}}+fp32-denormals,{{[^"]*}}-fp64-denormals{{[^"]*}}"
+// CHECK-FEATURE: attributes #{{[0-9]*}} = {{{[^}]*}} "target-features"="{{[^"]*}}+fp32-denormals,{{[^"]*}}-fp64-fp16-denormals{{[^"]*}}"
void f() {}
diff --git a/test/CodeGenOpenCL/gfx9-fp32-denorms.cl b/test/CodeGenOpenCL/gfx9-fp32-denorms.cl
new file mode 100644
index 000000000000..ccb4c6ddcf56
--- /dev/null
+++ b/test/CodeGenOpenCL/gfx9-fp32-denorms.cl
@@ -0,0 +1,13 @@
+// REQUIRES: amdgpu-registered-target
+
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu gfx900 -S -emit-llvm -o - %s | FileCheck --check-prefix=DEFAULT %s
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu gfx900 -S -emit-llvm -o - -target-feature +fp32-denormals %s | FileCheck --check-prefix=FEATURE_FP32_DENORMALS_ON %s
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu gfx900 -S -emit-llvm -o - -target-feature -fp32-denormals %s | FileCheck --check-prefix=FEATURE_FP32_DENORMALS_OFF %s
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu gfx900 -S -emit-llvm -o - -cl-denorms-are-zero %s | FileCheck --check-prefix=OPT_DENORMS_ARE_ZERO %s
+
+// DEFAULT: +fp32-denormals
+// FEATURE_FP32_DENORMALS_ON: +fp32-denormals
+// FEATURE_FP32_DENORMALS_OFF: -fp32-denormals
+// OPT_DENORMS_ARE_ZERO: -fp32-denormals
+
+kernel void gfx9_fp32_denorms() {}
diff --git a/test/CodeGenOpenCL/kernel-arg-info.cl b/test/CodeGenOpenCL/kernel-arg-info.cl
index 32017f85df8c..f1b2f45d7d97 100644
--- a/test/CodeGenOpenCL/kernel-arg-info.cl
+++ b/test/CodeGenOpenCL/kernel-arg-info.cl
@@ -2,7 +2,8 @@
// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -triple spir-unknown-unknown -cl-kernel-arg-info | FileCheck %s -check-prefix ARGINFO
kernel void foo(__global int * restrict X, const int Y,
- volatile int anotherArg, __constant float * restrict Z) {
+ volatile int anotherArg, __constant float * restrict Z,
+ __global volatile int * V, __global const int * C) {
*X = Y + anotherArg;
}
// CHECK: define spir_kernel void @foo{{[^!]+}}
@@ -60,11 +61,11 @@ kernel void foo5(myImage img1, write_only image1d_t img2) {
// CHECK-NOT: !kernel_arg_name
// ARGINFO: !kernel_arg_name ![[MD54:[0-9]+]]
-// CHECK: ![[MD11]] = !{i32 1, i32 0, i32 0, i32 2}
-// CHECK: ![[MD12]] = !{!"none", !"none", !"none", !"none"}
-// CHECK: ![[MD13]] = !{!"int*", !"int", !"int", !"float*"}
-// CHECK: ![[MD14]] = !{!"restrict", !"const", !"volatile", !"restrict const"}
-// ARGINFO: ![[MD15]] = !{!"X", !"Y", !"anotherArg", !"Z"}
+// CHECK: ![[MD11]] = !{i32 1, i32 0, i32 0, i32 2, i32 1, i32 1}
+// CHECK: ![[MD12]] = !{!"none", !"none", !"none", !"none", !"none", !"none"}
+// CHECK: ![[MD13]] = !{!"int*", !"int", !"int", !"float*", !"int*", !"int*"}
+// CHECK: ![[MD14]] = !{!"restrict", !"", !"", !"restrict const", !"volatile", !"const"}
+// ARGINFO: ![[MD15]] = !{!"X", !"Y", !"anotherArg", !"Z", !"V", !"C"}
// CHECK: ![[MD21]] = !{i32 1, i32 1, i32 1, i32 1}
// CHECK: ![[MD22]] = !{!"read_only", !"read_only", !"write_only", !"read_write"}
// CHECK: ![[MD23]] = !{!"image1d_t", !"image2d_t", !"image2d_array_t", !"image1d_t"}
diff --git a/test/CodeGenOpenCL/overload.cl b/test/CodeGenOpenCL/overload.cl
new file mode 100644
index 000000000000..f182cb5fd2af
--- /dev/null
+++ b/test/CodeGenOpenCL/overload.cl
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -cl-std=CL2.0 -emit-llvm -o - -triple spir-unknown-unknown %s | FileCheck %s
+
+typedef short short4 __attribute__((ext_vector_type(4)));
+
+// CHECK-DAG: declare spir_func <4 x i16> @_Z5clampDv4_sS_S_(<4 x i16>, <4 x i16>, <4 x i16>)
+short4 __attribute__ ((overloadable)) clamp(short4 x, short4 minval, short4 maxval);
+// CHECK-DAG: declare spir_func <4 x i16> @_Z5clampDv4_sss(<4 x i16>, i16 signext, i16 signext)
+short4 __attribute__ ((overloadable)) clamp(short4 x, short minval, short maxval);
+void __attribute__((overloadable)) foo(global int *a, global int *b);
+void __attribute__((overloadable)) foo(generic int *a, generic int *b);
+void __attribute__((overloadable)) bar(generic int *global *a, generic int *global *b);
+void __attribute__((overloadable)) bar(generic int *generic *a, generic int *generic *b);
+
+// Checking address space resolution
+void kernel test1() {
+ global int *a;
+ global int *b;
+ generic int *c;
+ local int *d;
+ generic int *generic *gengen;
+ generic int *local *genloc;
+ generic int *global *genglob;
+ // CHECK-DAG: call spir_func void @_Z3fooPU3AS1iS0_(i32 addrspace(1)* undef, i32 addrspace(1)* undef)
+ foo(a, b);
+ // CHECK-DAG: call spir_func void @_Z3fooPU3AS4iS0_(i32 addrspace(4)* undef, i32 addrspace(4)* undef)
+ foo(b, c);
+ // CHECK-DAG: call spir_func void @_Z3fooPU3AS4iS0_(i32 addrspace(4)* undef, i32 addrspace(4)* undef)
+ foo(a, d);
+
+ // CHECK-DAG: call spir_func void @_Z3barPU3AS4PU3AS4iS2_(i32 addrspace(4)* addrspace(4)* undef, i32 addrspace(4)* addrspace(4)* undef)
+ bar(gengen, genloc);
+ // CHECK-DAG: call spir_func void @_Z3barPU3AS4PU3AS4iS2_(i32 addrspace(4)* addrspace(4)* undef, i32 addrspace(4)* addrspace(4)* undef)
+ bar(gengen, genglob);
+ // CHECK-DAG: call spir_func void @_Z3barPU3AS1PU3AS4iS2_(i32 addrspace(4)* addrspace(1)* undef, i32 addrspace(4)* addrspace(1)* undef)
+ bar(genglob, genglob);
+}
+
+// Checking vector vs scalar resolution
+void kernel test2() {
+ short4 e0=0;
+
+ // CHECK-DAG: call spir_func <4 x i16> @_Z5clampDv4_sss(<4 x i16> zeroinitializer, i16 signext 0, i16 signext 255)
+ clamp(e0, 0, 255);
+ // CHECK-DAG: call spir_func <4 x i16> @_Z5clampDv4_sS_S_(<4 x i16> zeroinitializer, <4 x i16> zeroinitializer, <4 x i16> zeroinitializer)
+ clamp(e0, e0, e0);
+}
diff --git a/test/CodeGenOpenCL/preserve_vec3.cl b/test/CodeGenOpenCL/preserve_vec3.cl
new file mode 100644
index 000000000000..6efbbb3d5323
--- /dev/null
+++ b/test/CodeGenOpenCL/preserve_vec3.cl
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple spir-unknown-unknown -fpreserve-vec3-type | FileCheck %s
+
+typedef float float3 __attribute__((ext_vector_type(3)));
+typedef float float4 __attribute__((ext_vector_type(4)));
+
+void kernel foo(global float3 *a, global float3 *b) {
+ // CHECK: %[[LOAD_A:.*]] = load <3 x float>, <3 x float> addrspace(1)* %a
+ // CHECK: store <3 x float> %[[LOAD_A]], <3 x float> addrspace(1)* %b
+ *b = *a;
+}
+
+void kernel float4_to_float3(global float3 *a, global float4 *b) {
+ // CHECK: %[[LOAD_A:.*]] = load <4 x float>, <4 x float> addrspace(1)* %b, align 16
+ // CHECK: %[[ASTYPE:.*]] = shufflevector <4 x float> %[[LOAD_A]], <4 x float> undef, <3 x i32> <i32 0, i32 1, i32 2>
+ // CHECK: store <3 x float> %[[ASTYPE:.*]], <3 x float> addrspace(1)* %a, align 16
+ *a = __builtin_astype(*b, float3);
+}
+
+void kernel float3_to_float4(global float3 *a, global float4 *b) {
+ // CHECK: %[[LOAD_A:.*]] = load <3 x float>, <3 x float> addrspace(1)* %a, align 16
+ // CHECK: %[[ASTYPE:.*]] = shufflevector <3 x float> %[[LOAD_A]], <3 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 undef>
+ // CHECK: store <4 x float> %[[ASTYPE:.*]], <4 x float> addrspace(1)* %b, align 16
+ *b = __builtin_astype(*a, float4);
+}
diff --git a/test/CodeGenOpenCL/relaxed-fpmath.cl b/test/CodeGenOpenCL/relaxed-fpmath.cl
index 6f302b1335b6..7676ee164ce4 100644
--- a/test/CodeGenOpenCL/relaxed-fpmath.cl
+++ b/test/CodeGenOpenCL/relaxed-fpmath.cl
@@ -2,33 +2,54 @@
// RUN: %clang_cc1 %s -emit-llvm -cl-fast-relaxed-math -o - | FileCheck %s -check-prefix=FAST
// RUN: %clang_cc1 %s -emit-llvm -cl-finite-math-only -o - | FileCheck %s -check-prefix=FINITE
// RUN: %clang_cc1 %s -emit-llvm -cl-unsafe-math-optimizations -o - | FileCheck %s -check-prefix=UNSAFE
-
-typedef __attribute__(( ext_vector_type(4) )) float float4;
+// RUN: %clang_cc1 %s -emit-llvm -cl-mad-enable -o - | FileCheck %s -check-prefix=MAD
+// RUN: %clang_cc1 %s -emit-llvm -cl-no-signed-zeros -o - | FileCheck %s -check-prefix=NOSIGNED
float spscalardiv(float a, float b) {
// CHECK: @spscalardiv(
- // NORMAL: fdiv float
+ // NORMAL: fdiv float
// FAST: fdiv fast float
// FINITE: fdiv nnan ninf float
- // UNSAFE: fdiv nnan float
+ // UNSAFE: fdiv nnan nsz float
+ // MAD: fdiv float
+ // NOSIGNED: fdiv nsz float
return a / b;
}
// CHECK: attributes
+// NORMAL: "less-precise-fpmad"="false"
// NORMAL: "no-infs-fp-math"="false"
// NORMAL: "no-nans-fp-math"="false"
+// NORMAL: "no-signed-zeros-fp-math"="false"
// NORMAL: "unsafe-fp-math"="false"
+// FAST: "less-precise-fpmad"="true"
// FAST: "no-infs-fp-math"="true"
// FAST: "no-nans-fp-math"="true"
+// FAST: "no-signed-zeros-fp-math"="true"
// FAST: "unsafe-fp-math"="true"
+// FINITE: "less-precise-fpmad"="false"
// FINITE: "no-infs-fp-math"="true"
// FINITE: "no-nans-fp-math"="true"
+// FINITE: "no-signed-zeros-fp-math"="false"
// FINITE: "unsafe-fp-math"="false"
+// UNSAFE: "less-precise-fpmad"="true"
// UNSAFE: "no-infs-fp-math"="false"
// UNSAFE: "no-nans-fp-math"="true"
+// UNSAFE: "no-signed-zeros-fp-math"="true"
// UNSAFE: "unsafe-fp-math"="true"
+// MAD: "less-precise-fpmad"="true"
+// MAD: "no-infs-fp-math"="false"
+// MAD: "no-nans-fp-math"="false"
+// MAD: "no-signed-zeros-fp-math"="false"
+// MAD: "unsafe-fp-math"="false"
+
+// NOSIGNED: "less-precise-fpmad"="false"
+// NOSIGNED: "no-infs-fp-math"="false"
+// NOSIGNED: "no-nans-fp-math"="false"
+// NOSIGNED: "no-signed-zeros-fp-math"="true"
+// NOSIGNED: "unsafe-fp-math"="false"
diff --git a/test/CodeGenOpenCL/sampler.cl b/test/CodeGenOpenCL/sampler.cl
index 6fc8c2c68446..3a7319cd78d2 100644
--- a/test/CodeGenOpenCL/sampler.cl
+++ b/test/CodeGenOpenCL/sampler.cl
@@ -54,4 +54,8 @@ kernel void foo(sampler_t smp_par) {
fnc4smp(smp_par);
// CHECK: [[SAMP:%[0-9]+]] = load %opencl.sampler_t addrspace(2)*, %opencl.sampler_t addrspace(2)** [[smp_par_ptr]]
// CHECK: call spir_func void @fnc4smp(%opencl.sampler_t addrspace(2)* [[SAMP]])
+
+ fnc4smp(5);
+ // CHECK: [[SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 5)
+ // CHECK: call spir_func void @fnc4smp(%opencl.sampler_t addrspace(2)* [[SAMP]])
}
diff --git a/test/CodeGenOpenCL/vla.cl b/test/CodeGenOpenCL/vla.cl
index cbf98445ce00..5d3599fc3cce 100644
--- a/test/CodeGenOpenCL/vla.cl
+++ b/test/CodeGenOpenCL/vla.cl
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -emit-llvm -triple "spir-unknown-unknown" -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple "spir-unknown-unknown" -O0 -cl-std=CL2.0 -o - %s | FileCheck -check-prefixes=CHECK,SPIR %s
+// RUN: %clang_cc1 -emit-llvm -triple amdgcn-amd-amdhsa-opencl -O0 -cl-std=CL2.0 -o - %s | FileCheck -check-prefixes=CHECK,SPIR %s
+// RUN: %clang_cc1 -emit-llvm -triple amdgcn-amd-amdhsa-amdgizcl -O0 -cl-std=CL2.0 -o - %s | FileCheck -check-prefixes=CHECK,GIZ %s
constant int sz0 = 5;
// CHECK: @sz0 = addrspace(2) constant i32 5
@@ -11,8 +13,12 @@ const constant int sz2 = 8;
kernel void testvla()
{
int vla0[sz0];
-// CHECK: %vla0 = alloca [5 x i32]
+// SPIR: %vla0 = alloca [5 x i32]
+// SPIR-NOT: %vla0 = alloca [5 x i32]{{.*}}addrspace
+// GIZ: %vla0 = alloca [5 x i32]{{.*}}addrspace(5)
char vla1[sz1];
-// CHECK: %vla1 = alloca [16 x i8]
+// SPIR: %vla1 = alloca [16 x i8]
+// SPIR-NOT: %vla1 = alloca [16 x i8]{{.*}}addrspace
+// GIZ: %vla1 = alloca [16 x i8]{{.*}}addrspace(5)
local short vla2[sz2];
}
diff --git a/test/CoverageMapping/implicit-def-in-macro.m b/test/CoverageMapping/implicit-def-in-macro.m
index 902fc8bd6a77..71184fc78af9 100644
--- a/test/CoverageMapping/implicit-def-in-macro.m
+++ b/test/CoverageMapping/implicit-def-in-macro.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -triple x86_64-apple-darwin -fobjc-runtime=macosx-10.10.0 -fblocks -fobjc-arc %s | FileCheck %s
+// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -triple x86_64-apple-darwin -fobjc-runtime=macosx-10.10.0 -fblocks -fobjc-arc -w %s | FileCheck %s
@interface Foo
@end
diff --git a/test/CoverageMapping/macro-expressions.cpp b/test/CoverageMapping/macro-expressions.cpp
index 3852fc6a23b7..3eba86949a76 100644
--- a/test/CoverageMapping/macro-expressions.cpp
+++ b/test/CoverageMapping/macro-expressions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name macro-expressions.cpp %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name macro-expressions.cpp -w %s | FileCheck %s
#define EXPR(x) (x)
#define NEXPR(x) (!x)
diff --git a/test/CoverageMapping/objc.m b/test/CoverageMapping/objc.m
index 89da5da3203e..55c7545370cc 100644
--- a/test/CoverageMapping/objc.m
+++ b/test/CoverageMapping/objc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name objc.m -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
+// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name objc.m -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -w %s | FileCheck %s
@interface A
- (void)bork:(int)msg;
diff --git a/test/CoverageMapping/unused_names.c b/test/CoverageMapping/unused_names.c
index a03d18b6655d..bf0134c41ee4 100644
--- a/test/CoverageMapping/unused_names.c
+++ b/test/CoverageMapping/unused_names.c
@@ -2,14 +2,15 @@
// RUN: FileCheck -input-file %t %s
// RUN: FileCheck -check-prefix=SYSHEADER -input-file %t %s
-// Since foo is never emitted, there should not be a profile name for it.
+// CHECK-DAG: @__profc_bar
+// CHECK-DAG: @__llvm_prf_nm = private constant {{.*}}, section "{{.*__llvm_prf_names|.*lprfn}}"
-// CHECK-DAG: @__profn_bar = {{.*}} [3 x i8] c"bar"
-// CHECK-DAG: @__profn_baz = {{.*}} [3 x i8] c"baz"
-// CHECK-DAG: @__profn_unused_names.c_qux = {{.*}} [18 x i8] c"unused_names.c:qux"
-// CHECK-DAG: @__llvm_prf_nm = private constant {{.*}}, section "{{.*}}__llvm_prf_names"
+// These are never instantiated, so we shouldn't get counters for them.
+//
+// CHECK-NOT: @__profc_baz
+// CHECK-NOT: @__profc_unused_names.c_qux
-// SYSHEADER-NOT: @__profn_foo =
+// SYSHEADER-NOT: @__profc_foo =
#ifdef IS_SYSHEADER
diff --git a/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/aarch64/.keep b/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/aarch64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/aarch64/.keep
diff --git a/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/arm/.keep b/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/arm/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/arm/.keep
diff --git a/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/i386/.keep b/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/i386/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/i386/.keep
diff --git a/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64/.keep b/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64/.keep
diff --git a/test/Driver/XRay/xray-instrument-cpu.c b/test/Driver/XRay/xray-instrument-cpu.c
index 613342063a40..ee0e0984b36d 100644
--- a/test/Driver/XRay/xray-instrument-cpu.c
+++ b/test/Driver/XRay/xray-instrument-cpu.c
@@ -1,4 +1,4 @@
// RUN: not %clang -o /dev/null -v -fxray-instrument -c %s
-// XFAIL: amd64-, x86_64-, x86_64h-, arm, aarch64, arm64
+// XFAIL: amd64-, x86_64-, x86_64h-, arm, aarch64, arm64, powerpc64le-, mips, mipsel, mips64, mips64el
// REQUIRES: linux
typedef int a;
diff --git a/test/Driver/aarch64-cpus.c b/test/Driver/aarch64-cpus.c
index 88edcc5fc8d8..554c59d6bcdb 100644
--- a/test/Driver/aarch64-cpus.c
+++ b/test/Driver/aarch64-cpus.c
@@ -154,23 +154,23 @@
// RUN: %clang -target arm64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s
// ARM64-KRYO: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "kryo"
-// RUN: %clang -target aarch64 -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN %s
-// RUN: %clang -target aarch64 -mlittle-endian -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN %s
-// RUN: %clang -target aarch64 -mtune=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-TUNE %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-TUNE %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mtune=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-TUNE %s
-// VULCAN: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "vulcan" "-target-feature" "+v8.1a"
-// VULCAN-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "vulcan"
-// VULCAN-TUNE-NOT: +v8.1a
-
-// RUN: %clang -target arm64 -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-VULCAN %s
-// RUN: %clang -target arm64 -mlittle-endian -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-VULCAN %s
-// RUN: %clang -target arm64 -mtune=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-VULCAN-TUNE %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-VULCAN-TUNE %s
-// ARM64-VULCAN: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "vulcan" "-target-feature" "+v8.1a"
-// ARM64-VULCAN-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "vulcan"
-// ARM64-VULCAN-TUNE-NOT: +v8.1a
+// RUN: %clang -target aarch64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99 %s
+// RUN: %clang -target aarch64 -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-TUNE %s
+// THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "thunderx2t99" "-target-feature" "+v8.1a"
+// THUNDERX2T99-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "thunderx2t99"
+// THUNDERX2T99-TUNE-NOT: +v8.1a
+
+// RUN: %clang -target arm64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-THUNDERX2T99 %s
+// RUN: %clang -target arm64 -mlittle-endian -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-THUNDERX2T99 %s
+// RUN: %clang -target arm64 -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-THUNDERX2T99-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-THUNDERX2T99-TUNE %s
+// ARM64-THUNDERX2T99: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "thunderx2t99" "-target-feature" "+v8.1a"
+// ARM64-THUNDERX2T99-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "thunderx2t99"
+// ARM64-THUNDERX2T99-TUNE-NOT: +v8.1a
// RUN: %clang -target aarch64_be -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
// RUN: %clang -target aarch64 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
@@ -241,21 +241,21 @@
// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s
// M3-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m3"
-// RUN: %clang -target aarch64_be -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-BE %s
-// RUN: %clang -target aarch64_be -mtune=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=VULCAN-BE %s
-// VULCAN-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "vulcan"
+// RUN: %clang -target aarch64_be -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s
+// RUN: %clang -target aarch64_be -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s
+// THUNDERX2T99-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "thunderx2t99"
// RUN: %clang -target aarch64 -mcpu=cortex-a57 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// RUN: %clang -target aarch64 -mcpu=cortex-a72 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
-// RUN: %clang -target aarch64 -mcpu=vulcan -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
-// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
+// RUN: %clang -target aarch64 -mcpu=thunderx2t99 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
+// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// MCPU-MTUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53"
// RUN: %clang -target aarch64 -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
diff --git a/test/Driver/arch-specific-libdir-rpath.c b/test/Driver/arch-specific-libdir-rpath.c
new file mode 100644
index 000000000000..3bcf6e3d3f86
--- /dev/null
+++ b/test/Driver/arch-specific-libdir-rpath.c
@@ -0,0 +1,85 @@
+// Test that the driver adds an arch-specific subdirectory in
+// {RESOURCE_DIR}/lib/linux to the linker search path and to '-rpath'
+//
+// Test the default behavior when neither -frtlib-add-rpath nor
+// -fno-rtlib-add-rpath is specified, which is to skip -rpath
+// RUN: %clang %s -### 2>&1 -target x86_64-linux \
+// RUN: -fsanitize=address -shared-libasan \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,NO-RPATH-X86_64 %s
+//
+// Test that -rpath is not added under -fno-rtlib-add-rpath even if other
+// conditions are met.
+// RUN: %clang %s -### 2>&1 -target x86_64-linux \
+// RUN: -fsanitize=address -shared-libasan \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,NO-RPATH-X86_64 %s
+//
+// Test that -rpath is added only under the right circumstance even if
+// -frtlib-add-rpath is specified.
+//
+// Add LIBPATH but no RPATH for -fsanitizer=address w/o -shared-libasan
+// RUN: %clang %s -### 2>&1 -target x86_64-linux -fsanitize=undefined \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,NO-RPATH %s
+//
+// Add LIBPATH but no RPATH for -fsanitizer=address w/o -shared-libasan
+// RUN: %clang %s -### 2>&1 -target x86_64-linux -fsanitize=undefined \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,NO-RPATH %s
+//
+// Add LIBPATH, RPATH for -fsanitize=address -shared-libasan
+// RUN: %clang %s -### 2>&1 -target x86_64-linux \
+// RUN: -fsanitize=address -shared-libasan \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,RPATH-X86_64 %s
+//
+// Add LIBPATH, RPATH for -fsanitize=address -shared-libasan on aarch64
+// RUN: %clang %s -### 2>&1 -target aarch64-linux \
+// RUN: -fsanitize=address -shared-libasan \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-AArch64,RPATH-AArch64 %s
+//
+// Add LIBPATH, RPATH with -fsanitize=address for Android
+// RUN: %clang %s -### 2>&1 -target x86_64-linux-android -fsanitize=address \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,RPATH-X86_64 %s
+//
+// Add LIBPATH, RPATH for OpenMP
+// RUN: %clang %s -### 2>&1 -target x86_64-linux -fopenmp \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,RPATH-X86_64 %s
+//
+// Add LIBPATH but no RPATH for ubsan (or any other sanitizer)
+// RUN: %clang %s -### 2>&1 -fsanitize=undefined -target x86_64-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,NO-RPATH %s
+//
+// Add LIBPATH but no RPATH if no sanitizer or runtime is specified
+// RUN: %clang %s -### 2>&1 -target x86_64-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,LIBPATH-X86_64,NO-RPATH %s
+//
+// Do not add LIBPATH or RPATH if arch-specific subdir doesn't exist
+// RUN: %clang %s -### 2>&1 -target x86_64-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,NO-LIBPATH,NO-RPATH %s
+//
+// RESDIR: "-resource-dir" "[[RESDIR:[^"]*]]"
+// LIBPATH-X86_64: -L[[RESDIR]]{{(/|\\\\)lib(/|\\\\)linux(/|\\\\)x86_64}}
+// RPATH-X86_64: "-rpath" "[[RESDIR]]{{(/|\\\\)lib(/|\\\\)linux(/|\\\\)x86_64}}"
+// LIBPATH-AArch64: -L[[RESDIR]]{{(/|\\\\)lib(/|\\\\)linux(/|\\\\)aarch64}}
+// RPATH-AArch64: "-rpath" "[[RESDIR]]{{(/|\\\\)lib(/|\\\\)linux(/|\\\\)aarch64}}"
+// NO-LIBPATH-NOT: -L{{.*Inputs(/|\\\\)resource_dir}}
+// NO-RPATH-NOT: "-rpath" {{.*(/|\\\\)Inputs(/|\\\\)resource_dir}}
diff --git a/test/Driver/arch-specific-libdir.c b/test/Driver/arch-specific-libdir.c
new file mode 100644
index 000000000000..519236858b02
--- /dev/null
+++ b/test/Driver/arch-specific-libdir.c
@@ -0,0 +1,53 @@
+// Test that the driver adds an arch-specific subdirectory in
+// {RESOURCE_DIR}/lib/linux to the search path.
+//
+// RUN: %clang %s -### 2>&1 -target i386-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-i386 %s
+//
+// RUN: %clang %s -### 2>&1 -target i386-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s
+//
+// RUN: %clang %s -### 2>&1 -target i686-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-i386 %s
+//
+// RUN: %clang %s -### 2>&1 -target i686-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s
+//
+// RUN: %clang %s -### 2>&1 -target x86_64-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-x86_64 %s
+//
+// RUN: %clang %s -### 2>&1 -target x86_64-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s
+//
+// RUN: %clang %s -### 2>&1 -target arm-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-arm %s
+//
+// RUN: %clang %s -### 2>&1 -target arm-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s
+//
+// RUN: %clang %s -### 2>&1 -target aarch64-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,ARCHDIR-aarch64 %s
+//
+// RUN: %clang %s -### 2>&1 -target aarch64-unknown-linux \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: | FileCheck --check-prefixes=FILEPATH,NO-ARCHDIR %s
+//
+//
+// FILEPATH: "-x" "c" "[[FILE_PATH:.*]]{{(/|\\\\).*}}.c"
+// ARCHDIR-i386: -L[[FILE_PATH]]{{(/|\\\\)Inputs(/|\\\\)resource_dir_with_arch_subdir(/|\\\\)lib(/|\\\\)linux(/|\\\\)i386}}
+// ARCHDIR-x86_64: -L[[FILE_PATH]]{{(/|\\\\)Inputs(/|\\\\)resource_dir_with_arch_subdir(/|\\\\)lib(/|\\\\)linux(/|\\\\)x86_64}}
+// ARCHDIR-arm: -L[[FILE_PATH]]{{(/|\\\\)Inputs(/|\\\\)resource_dir_with_arch_subdir(/|\\\\)lib(/|\\\\)linux(/|\\\\)arm}}
+// ARCHDIR-aarch64: -L[[FILE_PATH]]{{(/|\\\\)Inputs(/|\\\\)resource_dir_with_arch_subdir(/|\\\\)lib(/|\\\\)linux(/|\\\\)aarch64}}
+//
+// Have a stricter check for no-archdir - that the driver doesn't add any
+// subdirectory from the provided resource directory.
+// NO-ARCHDIR-NOT: -L[[FILE_PATH]]/Inputs/resource_dir
diff --git a/test/Driver/arm-abi.c b/test/Driver/arm-abi.c
index 897c108048d4..ba5c4ba148ce 100644
--- a/test/Driver/arm-abi.c
+++ b/test/Driver/arm-abi.c
@@ -28,6 +28,10 @@
// RUN: %clang -target arm--netbsd-eabihf %s -### -o %t.o 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-AAPCS %s
+// OpenBSD defaults to aapcs-linux
+// RUN: %clang -target arm--openbsd- %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s
+
// Otherwise, ABI is selected based on environment
// RUN: %clang -target arm---android %s -### -o %t.o 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-AAPCS-LINUX %s
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
index 91268538e72f..c52e643f0337 100644
--- a/test/Driver/arm-cortex-cpus.c
+++ b/test/Driver/arm-cortex-cpus.c
@@ -579,6 +579,12 @@
// CHECK-CORTEX-A73-SOFT: "-target-feature" "+soft-float"
// CHECK-CORTEX-A73-SOFT: "-target-feature" "+soft-float-abi"
+// RUN: %clang -target arm -mcpu=cortex-m23 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8MBASE %s
+// CHECK-CPUV8MBASE: "-cc1"{{.*}} "-triple" "thumbv8m.base-
+
+// RUN: %clang -target arm -mcpu=cortex-m33 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8MMAIN %s
+// CHECK-CPUV8MMAIN: "-cc1"{{.*}} "-triple" "thumbv8m.main-
+
// ================== Check whether -mcpu accepts mixed-case values.
// RUN: %clang -target arm-linux-gnueabi -mcpu=Cortex-a5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CASE-INSENSITIVE-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-A7 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CASE-INSENSITIVE-CPUV7A %s
diff --git a/test/Driver/arm-execute-only.c b/test/Driver/arm-execute-only.c
index 7010bbc837a0..a4854485e1e4 100644
--- a/test/Driver/arm-execute-only.c
+++ b/test/Driver/arm-execute-only.c
@@ -90,6 +90,9 @@
// RUN: not %clang -target armv8m.main-eabi -mpure-code -mlong-calls %s 2>&1 \
// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY-LONG-CALLS
+// RUN: %clang -target armv7m-eabi -x assembler -mexecute-only %s -c -### 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY -check-prefix CHECK-NO-EXECUTE-ONLY-ASM
+
//
// CHECK-NO-EXECUTE-ONLY-NOT: "-backend-option" "-arm-execute-only"
// CHECK-EXECUTE-ONLY: "-backend-option" "-arm-execute-only"
@@ -97,3 +100,4 @@
// CHECK-EXECUTE-ONLY-NOT-SUPPORTED: error: execute only is not supported for the thumbv6m sub-architecture
// CHECK-EXECUTE-ONLY-NO-MOVT: error: option '-mexecute-only' cannot be specified with '-mno-movt'
// CHECK-EXECUTE-ONLY-LONG-CALLS: error: option '-mexecute-only' cannot be specified with '-mlong-calls'
+// CHECK-NO-EXECUTE-ONLY-ASM: warning: argument unused during compilation: '-mexecute-only'
diff --git a/test/Driver/arm-no-neg-immediates.c b/test/Driver/arm-no-neg-immediates.c
new file mode 100644
index 000000000000..f1e4d5f7906b
--- /dev/null
+++ b/test/Driver/arm-no-neg-immediates.c
@@ -0,0 +1,8 @@
+// RUN: %clang -target arm-none-gnueabi -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT
+// RUN: %clang -target arm-none-gnueabi -mno-neg-immediates -### %s 2>&1 | FileCheck %s
+
+// RUN: %clang -target aarch64-none-gnueabi -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT
+// RUN: %clang -target aarch64-none-gnueabi -mno-neg-immediates -### %s 2>&1 | FileCheck %s
+
+// CHECK: "-target-feature" "+no-neg-immediates"
+// CHECK-DEFAULT-NOT: "+no-neg-immediates"
diff --git a/test/Driver/cl-link-at-file.c b/test/Driver/cl-link-at-file.c
index 3a37e2f476e4..50ae07fadf5b 100644
--- a/test/Driver/cl-link-at-file.c
+++ b/test/Driver/cl-link-at-file.c
@@ -13,7 +13,6 @@
// be clueless and will emit "argument unused" warnings. If PR17239 is properly
// fixed, this should not happen because the "/link" option is restricted to
// consume only remaining args in its response file.
-// ARGS-NOT: warning
// ARGS-NOT: argument unused during compilation
// Identify the linker command
// ARGS: link.exe
diff --git a/test/Driver/cl-link.c b/test/Driver/cl-link.c
index b195676250e8..4cc170c1cbb8 100644
--- a/test/Driver/cl-link.c
+++ b/test/Driver/cl-link.c
@@ -13,8 +13,10 @@
// ASAN: link.exe
// ASAN: "-debug"
// ASAN: "-incremental:no"
-// ASAN: "{{.*}}clang_rt.asan-i386.lib"
-// ASAN: "{{.*}}clang_rt.asan_cxx-i386.lib"
+// ASAN: "{{[^"]*}}clang_rt.asan-i386.lib"
+// ASAN: "-wholearchive:{{.*}}clang_rt.asan-i386.lib"
+// ASAN: "{{[^"]*}}clang_rt.asan_cxx-i386.lib"
+// ASAN: "-wholearchive:{{.*}}clang_rt.asan_cxx-i386.lib"
// ASAN: "{{.*}}cl-link{{.*}}.obj"
// RUN: %clang_cl -m32 -arch:IA32 --target=i386-pc-win32 /MD /Tc%s -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN-MD %s
@@ -22,8 +24,9 @@
// ASAN-MD: "-debug"
// ASAN-MD: "-incremental:no"
// ASAN-MD: "{{.*}}clang_rt.asan_dynamic-i386.lib"
-// ASAN-MD: "{{.*}}clang_rt.asan_dynamic_runtime_thunk-i386.lib"
+// ASAN-MD: "{{[^"]*}}clang_rt.asan_dynamic_runtime_thunk-i386.lib"
// ASAN-MD: "-include:___asan_seh_interceptor"
+// ASAN-MD: "-wholearchive:{{.*}}clang_rt.asan_dynamic_runtime_thunk-i386.lib"
// ASAN-MD: "{{.*}}cl-link{{.*}}.obj"
// RUN: %clang_cl /LD -### /Tc%s 2>&1 | FileCheck --check-prefix=DLL %s
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index 69238227c542..c425e21dd7fb 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -442,6 +442,12 @@
// Xclang: "-cc1"
// Xclang: "hellocc1"
+// Files under /Users are often confused with the /U flag. (This could happen
+// for other flags too, but this is the one people run into.)
+// RUN: %clang_cl /c /Users/me/myfile.c -### 2>&1 | FileCheck -check-prefix=SlashU %s
+// SlashU: warning: '/Users/me/myfile.c' treated as the '/U' option
+// SlashU: note: Use '--' to treat subsequent arguments as filenames
+
// RTTI is on by default. /GR- controls -fno-rtti-data.
// RUN: %clang_cl /c /GR- -### -- %s 2>&1 | FileCheck -check-prefix=NoRTTI %s
// NoRTTI: "-fno-rtti-data"
@@ -516,6 +522,15 @@
// RUN: env CL="%s" _CL_="%s" not %clang --rsp-quoting=windows -c
+// RUN: %clang_cl -### /c -flto -- %s 2>&1 | FileCheck -check-prefix=LTO %s
+// LTO: -flto
+
+// RUN: %clang_cl -### /c -flto=thin -- %s 2>&1 | FileCheck -check-prefix=LTO-THIN %s
+// LTO-THIN: -flto=thin
+
+// RUN: %clang_cl -### -Fe%t.exe -entry:main -flto -- %s 2>&1 | FileCheck -check-prefix=LTO-WITHOUT-LLD %s
+// LTO-WITHOUT-LLD: LTO requires -fuse-ld=lld
+
// Accept "core" clang options.
// (/Zs is for syntax-only, -Werror makes it fail hard on unknown options)
// RUN: %clang_cl \
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index 210e16935d81..15c1eacb9617 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -59,6 +59,13 @@
// RUN: %clang -### -S -fauto-profile=%S/Inputs/file.prof %s 2>&1 | FileCheck -check-prefix=CHECK-AUTO-PROFILE %s
// CHECK-AUTO-PROFILE: "-fprofile-sample-use={{.*}}/file.prof"
+// RUN: %clang -### -S -fauto-profile=%S/Inputs/file.prof -fno-profile-sample-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-AUTO-PROFILE %s
+// RUN: %clang -### -S -fauto-profile=%S/Inputs/file.prof -fno-auto-profile %s 2>&1 | FileCheck -check-prefix=CHECK-NO-AUTO-PROFILE %s
+// CHECK-NO-AUTO-PROFILE-NOT: "-fprofile-sample-use={{.*}}/file.prof"
+
+// RUN: %clang -### -S -fauto-profile=%S/Inputs/file.prof -fno-profile-sample-use -fauto-profile %s 2>&1 | FileCheck -check-prefix=CHECK-AUTO-PROFILE %s
+// RUN: %clang -### -S -fauto-profile=%S/Inputs/file.prof -fno-auto-profile -fprofile-sample-use %s 2>&1 | FileCheck -check-prefix=CHECK-AUTO-PROFILE %s
+
// RUN: %clang -### -S -fprofile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-ARCS %s
// RUN: %clang -### -S -fno-profile-arcs -fprofile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-ARCS %s
// RUN: %clang -### -S -fno-profile-arcs %s 2>&1 | FileCheck -check-prefix=CHECK-NO-PROFILE-ARCS %s
@@ -482,3 +489,8 @@
// RUN: %clang -### -S -fno-strict-return %s 2>&1 | FileCheck -check-prefix=CHECK-NO-STRICT-RETURN %s
// CHECK-STRICT-RETURN-NOT: "-fno-strict-return"
// CHECK-NO-STRICT-RETURN: "-fno-strict-return"
+
+// RUN: %clang -### -S -fno-debug-info-for-profiling -fdebug-info-for-profiling %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-DEBUG %s
+// RUN: %clang -### -S -fdebug-info-for-profiling -fno-debug-info-for-profiling %s 2>&1 | FileCheck -check-prefix=CHECK-NO-PROFILE-DEBUG %s
+// CHECK-PROFILE-DEBUG: -fdebug-info-for-profiling
+// CHECK-NO-PROFILE-DEBUG-NOT: -fdebug-info-for-profiling
diff --git a/test/Driver/crash-report-crashfile.m b/test/Driver/crash-report-crashfile.m
index 71f6e7a9e129..fbfb532703ef 100644
--- a/test/Driver/crash-report-crashfile.m
+++ b/test/Driver/crash-report-crashfile.m
@@ -3,15 +3,32 @@
// RUN: mkdir -p %t/i %t/m %t
// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH= TMPDIR=%t TEMP=%t TMP=%t \
-// RUN: %clang -fsyntax-only %s -I %S/Inputs/module -isysroot %/t/i/ \
-// RUN: -fmodules -fmodules-cache-path=%t/m/ -DFOO=BAR 2>&1 | FileCheck %s
+// RUN: %clang -fsyntax-only %s \
+// RUN: -I %S/Inputs/module -isysroot %/t/i/ \
+// RUN: -fmodules -fmodules-cache-path=%t/m/ -DFOO=BAR 2>&1 | \
+// RUN: FileCheck -check-prefix=CRASH_ENV %s
+
+// RUN: not env TMPDIR=%t TEMP=%t TMP=%t \
+// RUN: %clang -gen-reproducer -fsyntax-only %s \
+// RUN: -I %S/Inputs/module -isysroot %/t/i/ \
+// RUN: -fmodules -fmodules-cache-path=%t/m/ -DFOO=BAR 2>&1 | \
+// RUN: FileCheck -check-prefix=CRASH_FLAG %s
@import simple;
const int x = MODULE_MACRO;
-// CHECK: Preprocessed source(s) and associated run script(s) are located at:
-// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
-// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
-// CHECK-NEXT: note: diagnostic msg: {{.*}}.sh
-// CHECK-NEXT: note: diagnostic msg: Crash backtrace is located in
-// CHECK-NEXT: note: diagnostic msg: {{.*}}Library/Logs/DiagnosticReports{{.*}}
+// CRASH_ENV: failing because environment variable 'FORCE_CLANG_DIAGNOSTICS_CRASH' is set
+// CRASH_ENV: Preprocessed source(s) and associated run script(s) are located at:
+// CRASH_ENV-NEXT: note: diagnostic msg: {{.*}}.m
+// CRASH_ENV-NEXT: note: diagnostic msg: {{.*}}.cache
+// CRASH_ENV-NEXT: note: diagnostic msg: {{.*}}.sh
+// CRASH_ENV-NEXT: note: diagnostic msg: Crash backtrace is located in
+// CRASH_ENV-NEXT: note: diagnostic msg: {{.*}}Library/Logs/DiagnosticReports{{.*}}
+
+// CRASH_FLAG: failing because '-gen-reproducer' is used
+// CRASH_FLAG: Preprocessed source(s) and associated run script(s) are located at:
+// CRASH_FLAG-NEXT: note: diagnostic msg: {{.*}}.m
+// CRASH_FLAG-NEXT: note: diagnostic msg: {{.*}}.cache
+// CRASH_FLAG-NEXT: note: diagnostic msg: {{.*}}.sh
+// CRASH_FLAG-NEXT: note: diagnostic msg: Crash backtrace is located in
+// CRASH_FLAG-NEXT: note: diagnostic msg: {{.*}}Library/Logs/DiagnosticReports{{.*}}
diff --git a/test/Driver/cuda-no-stack-protector.cu b/test/Driver/cuda-no-stack-protector.cu
new file mode 100644
index 000000000000..f94cc188fac0
--- /dev/null
+++ b/test/Driver/cuda-no-stack-protector.cu
@@ -0,0 +1,23 @@
+// Check that -stack-protector doesn't get passed down to device-side
+// compilation.
+//
+// REQUIRES: clang-driver
+//
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_20 \
+// RUN: -fstack-protector-all %s 2>&1 | \
+// RUN: FileCheck %s
+//
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_20 \
+// RUN: -fstack-protector-strong %s 2>&1 | \
+// RUN: FileCheck %s
+//
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_20 \
+// RUN: -fstack-protector %s 2>&1 | \
+// RUN: FileCheck %s
+//
+// CHECK-NOT: error: unsupported option '-fstack-protector
+// CHECK-DAG: "-fcuda-is-device"
+// CHECK-NOT: "-stack-protector"
+// CHECK-NOT: "-stack-protector-buffer-size"
+// CHECK-DAG: "-triple" "x86_64--linux-gnu"
+// CHECK: "-stack-protector"
diff --git a/test/Driver/darwin-ld-pthread.c b/test/Driver/darwin-ld-pthread.c
new file mode 100644
index 000000000000..b22b68a6e623
--- /dev/null
+++ b/test/Driver/darwin-ld-pthread.c
@@ -0,0 +1,4 @@
+// RUN: %clang -Wunused-command-line-argument -pthread -target x86_64-apple-darwin -### /dev/null -o /dev/null 2>&1 | FileCheck %s
+
+// There is nothing to do at link time to get pthread support. But do not warn.
+// CHECK-NOT: argument unused during compilation: '-pthread'
diff --git a/test/Driver/darwin-simulator-macro.c b/test/Driver/darwin-simulator-macro.c
new file mode 100644
index 000000000000..6971e9303a6d
--- /dev/null
+++ b/test/Driver/darwin-simulator-macro.c
@@ -0,0 +1,12 @@
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -mios-simulator-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=SIM %s
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -miphonesimulator-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=SIM %s
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -mtvos-simulator-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=SIM %s
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -mappletvsimulator-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=SIM %s
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -mwatchos-simulator-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=SIM %s
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -mwatchsimulator-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=SIM %s
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -mios-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=DEV %s
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -mtvos-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=DEV %s
+// RUN: %clang -target x86_64-apple-darwin10 -arch x86_64 -mwatchos-version-min=6.0.0 -E -dM %s | FileCheck -check-prefix=DEV %s
+
+// SIM: #define __APPLE_EMBEDDED_SIMULATOR__ 1
+// DEV-NOT: __APPLE_EMBEDDED_SIMULATOR__
diff --git a/test/Driver/debug-options.c b/test/Driver/debug-options.c
index 94c769fa37d3..74deb414fc56 100644
--- a/test/Driver/debug-options.c
+++ b/test/Driver/debug-options.c
@@ -117,8 +117,18 @@
// RUN: %clang -### -c -gline-tables-only -g0 %s 2>&1 \
// RUN: | FileCheck -check-prefix=GLTO_NO %s
//
-// RUN: %clang -### -c -grecord-gcc-switches -gno-record-gcc-switches \
-// RUN: -gstrict-dwarf -gno-strict-dwarf %s 2>&1 \
+// RUN: %clang -### -c -grecord-gcc-switches %s 2>&1 \
+// | FileCheck -check-prefix=GRECORD %s
+// RUN: %clang -### -c -gno-record-gcc-switches %s 2>&1 \
+// | FileCheck -check-prefix=GNO_RECORD %s
+// RUN: %clang -### -c -grecord-gcc-switches -gno-record-gcc-switches %s 2>&1 \
+// | FileCheck -check-prefix=GNO_RECORD %s/
+// RUN: %clang -### -c -grecord-gcc-switches -o - %s 2>&1 \
+// | FileCheck -check-prefix=GRECORD_O %s
+// RUN: %clang -### -c -O3 -ffunction-sections -grecord-gcc-switches %s 2>&1 \
+// | FileCheck -check-prefix=GRECORD_OPT %s
+//
+// RUN: %clang -### -c -gstrict-dwarf -gno-strict-dwarf %s 2>&1 \
// RUN: | FileCheck -check-prefix=GIGNORE %s
//
// RUN: %clang -### -c -ggnu-pubnames %s 2>&1 | FileCheck -check-prefix=GOPT %s
@@ -194,6 +204,17 @@
// GLTO_NO: "-cc1"
// GLTO_NO-NOT: -debug-info-kind=
//
+// GRECORD: "-dwarf-debug-flags"
+// GRECORD: -### -c -grecord-gcc-switches
+//
+// GNO_RECORD-NOT: "-dwarf-debug-flags"
+// GNO_RECORD-NOT: -### -c -grecord-gcc-switches
+//
+// GRECORD_O: "-dwarf-debug-flags"
+// GRECORD_O: -### -c -grecord-gcc-switches -o -
+//
+// GRECORD_OPT: -### -c -O3 -ffunction-sections -grecord-gcc-switches
+//
// GIGNORE-NOT: "argument unused during compilation"
//
// GOPT: -generate-gnu-dwarf-pub-sections
@@ -214,3 +235,9 @@
// BADSTRING1: error: invalid value 'watkind' in '-debug-info-kind=watkind'
// RUN: not %clang -cc1 -debugger-tuning=gmodal 2>&1 | FileCheck -check-prefix=BADSTRING2 %s
// BADSTRING2: error: invalid value 'gmodal' in '-debugger-tuning=gmodal'
+
+// RUN: %clang -### -fdebug-macro %s 2>&1 | FileCheck -check-prefix=MACRO %s
+// RUN: %clang -### -fno-debug-macro %s 2>&1 | FileCheck -check-prefix=NOMACRO %s
+// RUN: %clang -### %s 2>&1 | FileCheck -check-prefix=NOMACRO %s
+// MACRO: "-debug-info-macro"
+// NOMACRO-NOT: "-debug-info-macro"
diff --git a/test/Driver/embed-bitcode.c b/test/Driver/embed-bitcode.c
index 36314e664093..07e4378dc094 100644
--- a/test/Driver/embed-bitcode.c
+++ b/test/Driver/embed-bitcode.c
@@ -34,6 +34,13 @@
// CHECK-LTO-NOT: warning: argument unused during compilation: '-fembed-bitcode'
// CHECK-LTO-NOT: -cc1
// CHECK-LTO-NOT: -fembed-bitcode=all
+// RUN: touch %t.o
+// RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=6.0 %t.o -fembed-bitcode -fembed-bitcode-marker -mlinker-version=277 2>&1 -### | FileCheck %s -check-prefix=CHECK-LTO-MARKER-277
+// RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=6.0 %t.o -fembed-bitcode -fembed-bitcode-marker -mlinker-version=278 2>&1 -### | FileCheck %s -check-prefix=CHECK-LTO-MARKER-278
+// CHECK-LTO-MARKER-277-NOT: bitcode_process_mode
+// CHECK-LTO-MARKER-278: bitcode_process_mode
+
+
// RUN: %clang -c %s -fembed-bitcode-marker -fintegrated-as 2>&1 -### | FileCheck %s -check-prefix=CHECK-MARKER
// CHECK-MARKER: -cc1
@@ -51,5 +58,5 @@
// CHECK-NO-LINKER-NOT: -bitcode_bundle
// RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=5.0 %s -fembed-bitcode -### 2>&1 | \
-// RUN: FileCheck %s -check-prefix=CHECK-PLATFORM-UNSUPPORTED
-// CHECK-PLATFORM-UNSUPPORTED: -fembed-bitcode is not supported on versions of iOS prior to 6.0
+// RUN: FileCheck %s -check-prefix=CHECK-PLATFORM-NOTSUPPORTED
+// CHECK-PLATFORM-NOTSUPPORTED: -fembed-bitcode is not supported on versions of iOS prior to 6.0
diff --git a/test/Driver/fast-math.c b/test/Driver/fast-math.c
index 025651d0a395..97fda009b9cf 100644
--- a/test/Driver/fast-math.c
+++ b/test/Driver/fast-math.c
@@ -148,20 +148,31 @@
//
// One umbrella flag is *really* weird and also changes the semantics of the
// program by adding a special preprocessor macro. Check that the frontend flag
-// modeling this semantic change is provided. Also check that the semantic
-// impact remains even if every optimization is disabled.
+// modeling this semantic change is provided. Also check that the flag is not
+// present if any of the optimization is disabled.
// RUN: %clang -### -ffast-math -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
// RUN: %clang -### -fno-fast-math -ffast-math -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
-// RUN: %clang -### -ffast-math -fno-finite-math-only \
-// RUN: -fno-unsafe-math-optimizations -fmath-errno -c %s 2>&1 \
+// RUN: %clang -### -funsafe-math-optimizations -ffinite-math-only \
+// RUN: -fno-math-errno -ffp-contract=fast -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
+// RUN: %clang -### -fno-honor-infinities -fno-honor-nans -fno-math-errno \
+// RUN: -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN: -fno-trapping-math -ffp-contract=fast -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
// CHECK-FAST-MATH: "-cc1"
// CHECK-FAST-MATH: "-ffast-math"
+// CHECK-FAST-MATH: "-ffinite-math-only"
//
// RUN: %clang -### -ffast-math -fno-fast-math -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH %s
+// RUN: %clang -### -ffast-math -fno-finite-math-only -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH %s
+// RUN: %clang -### -ffast-math -fno-unsafe-math-optimizations -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH %s
+// RUN: %clang -### -ffast-math -fmath-errno -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH %s
// CHECK-NO-FAST-MATH: "-cc1"
// CHECK-NO-FAST-MATH-NOT: "-ffast-math"
//
@@ -179,6 +190,7 @@
// RUN: | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
// CHECK-NO-NO-INFS: "-cc1"
// CHECK-NO-NO-INFS-NOT: "-menable-no-infs"
+// CHECK-NO-NO-INFS-NOT: "-ffinite-math-only"
// CHECK-NO-NO-INFS: "-o"
//
// RUN: %clang -### -fno-honor-nans -fhonor-nans -c %s 2>&1 \
@@ -193,6 +205,7 @@
// RUN: | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
// CHECK-NO-NO-NANS: "-cc1"
// CHECK-NO-NO-NANS-NOT: "-menable-no-nans"
+// CHECK-NO-NO-NANS-NOT: "-ffinite-math-only"
// CHECK-NO-NO-NANS: "-o"
//
// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
diff --git a/test/Driver/frame-pointer-elim.c b/test/Driver/frame-pointer-elim.c
index e1d816ea9fd1..e39499a55c24 100644
--- a/test/Driver/frame-pointer-elim.c
+++ b/test/Driver/frame-pointer-elim.c
@@ -49,9 +49,9 @@
// RUN: %clang -### -target armv7s-apple-ios8.0 -momit-leaf-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=WARN-OMIT-LEAF-7S %s
-// WARN-OMIT-LEAF-7S: warning: optimization flag '-momit-leaf-frame-pointer' is not supported for target 'armv7s'
+// WARN-OMIT-LEAF-7S-NOT: warning: optimization flag '-momit-leaf-frame-pointer' is not supported for target 'armv7s'
// WARN-OMIT-LEAF-7S: "-mdisable-fp-elim"
-// WARN-OMIT-LEAF-7S-NOT: "-momit-leaf-frame-pointer"
+// WARN-OMIT-LEAF-7S: "-momit-leaf-frame-pointer"
// On the PS4, we default to omitting the frame pointer on leaf functions
// (OMIT_LEAF check line is above)
diff --git a/test/Driver/frame-pointer.c b/test/Driver/frame-pointer.c
index cec168636c13..ecb16af3cf80 100644
--- a/test/Driver/frame-pointer.c
+++ b/test/Driver/frame-pointer.c
@@ -17,6 +17,13 @@
// RUN: %clang -target s390x-pc-linux -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-64 %s
// RUN: %clang -target s390x-pc-linux -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-64 %s
+// RUN: %clang -target powerpc-unknown-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-64 %s
+// RUN: %clang -target powerpc-unknown-linux-gnu -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-64 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-64 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-64 %s
+// RUN: %clang -target powerpc64le-unknown-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-64 %s
+// RUN: %clang -target powerpc64le-unknown-linux-gnu -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-64 %s
+
// RUN: %clang -target mips-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-32 %s
// RUN: %clang -target mips-linux-gnu -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-32 %s
// RUN: %clang -target mipsel-linux-gnu -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-32 %s
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
index 25aea01aae5d..b6304b515b73 100644
--- a/test/Driver/fsanitize.c
+++ b/test/Driver/fsanitize.c
@@ -109,19 +109,22 @@
// CHECK-SANE-SANKA: '-fsanitize=efficiency-{{.*}}' not allowed with '-fsanitize=kernel-address'
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-use-after-scope %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE
+// RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fsanitize-address-use-after-scope -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE
// CHECK-USE-AFTER-SCOPE: -cc1{{.*}}-fsanitize-address-use-after-scope
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fno-sanitize-address-use-after-scope %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE-OFF
+// RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fno-sanitize-address-use-after-scope -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE-OFF
// CHECK-USE-AFTER-SCOPE-OFF-NOT: -cc1{{.*}}address-use-after-scope
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fno-sanitize-address-use-after-scope -fsanitize-address-use-after-scope %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE-BOTH
+// RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fno-sanitize-address-use-after-scope -fsanitize-address-use-after-scope -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE-BOTH
// CHECK-USE-AFTER-SCOPE-BOTH: -cc1{{.*}}-fsanitize-address-use-after-scope
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-use-after-scope -fno-sanitize-address-use-after-scope %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE-BOTH-OFF
// CHECK-USE-AFTER-SCOPE-BOTH-OFF-NOT: -cc1{{.*}}address-use-after-scope
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-WITHOUT-USE-AFTER-SCOPE
-// CHECK-ASAN-WITHOUT-USE-AFTER-SCOPE-NOT: -cc1{{.*}}address-use-after-scope
+// CHECK-ASAN-WITHOUT-USE-AFTER-SCOPE: -cc1{{.*}}address-use-after-scope
// RUN: %clang -target x86_64-linux-gnu -fsanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-TRACK-ORIGINS
// CHECK-ONLY-TRACK-ORIGINS: warning: argument unused during compilation: '-fsanitize-memory-track-origins'
@@ -231,6 +234,36 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,leak -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANL-NO-SANA
// CHECK-SANA-SANL-NO-SANA: "-fsanitize=leak"
+// RUN: %clang -target i686-linux-gnu -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-X86
+// CHECK-SANL-X86: "-fsanitize=leak"
+
+// RUN: %clang -target i686-linux-gnu -fsanitize=address,leak -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANL-NO-SANA-X86
+// CHECK-SANA-SANL-NO-SANA-X86: "-fsanitize=leak"
+
+// RUN: %clang -target arm-linux-gnu -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-ARM
+// CHECK-SANL-ARM: "-fsanitize=leak"
+
+// RUN: %clang -target arm-linux-gnu -fsanitize=address,leak -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANL-NO-SANA-ARM
+// CHECK-SANA-SANL-NO-SANA-ARM: "-fsanitize=leak"
+
+// RUN: %clang -target thumb-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-THUMB
+// CHECK-SANL-THUMB: "-fsanitize=leak"
+
+// RUN: %clang -target thumb-linux -fsanitize=address,leak -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANL-NO-SANA-THUMB
+// CHECK-SANA-SANL-NO-SANA-THUMB: "-fsanitize=leak"
+
+// RUN: %clang -target armeb-linux-gnu -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-ARMEB
+// CHECK-SANL-ARMEB: "-fsanitize=leak"
+
+// RUN: %clang -target armeb-linux-gnu -fsanitize=address,leak -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANL-NO-SANA-ARMEB
+// CHECK-SANA-SANL-NO-SANA-ARMEB: "-fsanitize=leak"
+
+// RUN: %clang -target thumbeb-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-THUMBEB
+// CHECK-SANL-THUMBEB: "-fsanitize=leak"
+
+// RUN: %clang -target thumbeb-linux -fsanitize=address,leak -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANL-NO-SANA-THUMBEB
+// CHECK-SANA-SANL-NO-SANA-THUMBEB: "-fsanitize=leak"
+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN
// CHECK-MSAN: "-fno-assume-sane-operator-new"
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN
diff --git a/test/Driver/fuchsia.c b/test/Driver/fuchsia.c
index 75172edf6b27..58c2bbe533c9 100644
--- a/test/Driver/fuchsia.c
+++ b/test/Driver/fuchsia.c
@@ -38,3 +38,8 @@
// CHECK-RELOCATABLE-NOT: "-pie"
// CHECK-RELOCATABLE-NOT: "--build-id"
// CHECK-RELOCATABLE: "-r"
+
+// RUN: %clang %s -### --target=x86_64-unknown-fuchsia \
+// RUN: -fsanitize=safe-stack 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-SAFESTACK
+// CHECK-SAFESTACK: "-fsanitize=safe-stack"
diff --git a/test/Driver/hexagon-toolchain-elf.c b/test/Driver/hexagon-toolchain-elf.c
index 827c19186b44..f6f2191b3eb6 100644
--- a/test/Driver/hexagon-toolchain-elf.c
+++ b/test/Driver/hexagon-toolchain-elf.c
@@ -89,6 +89,14 @@
// CHECK023: "-cc1" {{.*}} "-target-cpu" "hexagonv60"
// CHECK023: hexagon-link{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v60/crt0
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv62 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK024 %s
+// CHECK024: "-cc1" {{.*}} "-target-cpu" "hexagonv62"
+// CHECK024: hexagon-link{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v62/crt0
+
// -----------------------------------------------------------------------------
// Test Linker related args
// -----------------------------------------------------------------------------
diff --git a/test/Driver/immediate-options.c b/test/Driver/immediate-options.c
index f50ccae64217..935c948321f5 100644
--- a/test/Driver/immediate-options.c
+++ b/test/Driver/immediate-options.c
@@ -12,3 +12,8 @@
// RUN: %clang -print-search-dirs | FileCheck %s -check-prefix=PRINT-SEARCH-DIRS
// PRINT-SEARCH-DIRS: programs: ={{.*}}
// PRINT-SEARCH-DIRS: libraries: ={{.*}}
+
+// Test if the -print-resource-dir option is accepted without error.
+// Allow unspecified output because the value of CLANG_RESOURCE_DIR is unknown.
+// RUN: %clang -print-resource-dir | FileCheck %s -check-prefix=PRINT-RESOURCE-DIR
+// PRINT-RESOURCE-DIR: {{.+}}
diff --git a/test/Driver/include-default-header.cl b/test/Driver/include-default-header.cl
new file mode 100644
index 000000000000..2605eaead9c1
--- /dev/null
+++ b/test/Driver/include-default-header.cl
@@ -0,0 +1,6 @@
+// RUN: %clang -save-temps -x cl -Xclang -cl-std=CL2.0 -Xclang -finclude-default-header -emit-llvm -S -### %s
+// CHECK-NOT: finclude-default-header
+// Make sure we don't pass -finclude-default-header to any commands other than the driver.
+
+void test() {}
+
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index 5d1001beb02c..e5aa870866d2 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -705,6 +705,14 @@
// CHECK-PPC64LE-ELFv2: "-m" "elf64lppc"
// CHECK-PPC64LE-ELFv2: "-dynamic-linker" "{{.*}}/lib{{(64)?}}/ld64.so.2"
//
+// Check that we do not pass --hash-style=gnu or --hash-style=both to
+// hexagon linux linker
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: --target=hexagon-linux-gnu \
+// RUN: | FileCheck --check-prefix=CHECK-HEXAGON %s
+// CHECK-HEXAGON: "{{.*}}hexagon-link{{(.exe)?}}"
+// CHECK-HEXAGON-NOT: "--hash-style={{gnu|both}}"
+//
// Check that we do not pass --hash-style=gnu and --hash-style=both to linker
// and provide correct path to the dynamic linker and emulation mode when build
// for MIPS platforms.
diff --git a/test/Driver/lto-unit.c b/test/Driver/lto-unit.c
new file mode 100644
index 000000000000..8a800fa4dcd6
--- /dev/null
+++ b/test/Driver/lto-unit.c
@@ -0,0 +1,7 @@
+// RUN: %clang -target x86_64-unknown-linux -### %s -flto=full 2>&1 | FileCheck --check-prefix=UNIT %s
+// RUN: %clang -target x86_64-unknown-linux -### %s -flto=thin 2>&1 | FileCheck --check-prefix=UNIT %s
+// RUN: %clang -target x86_64-apple-darwin13.3.0 -### %s -flto=full 2>&1 | FileCheck --check-prefix=UNIT %s
+// RUN: %clang -target x86_64-apple-darwin13.3.0 -### %s -flto=thin 2>&1 | FileCheck --check-prefix=NOUNIT %s
+
+// UNIT: "-flto-unit"
+// NOUNIT-NOT: "-flto-unit"
diff --git a/test/Driver/mglobal-merge.c b/test/Driver/mglobal-merge.c
index ad76736a69c1..271011e985c5 100644
--- a/test/Driver/mglobal-merge.c
+++ b/test/Driver/mglobal-merge.c
@@ -11,7 +11,7 @@
// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
// CHECK-NGM-ARM: "-backend-option" "-arm-global-merge=false"
-// CHECK-NGM-AARCH64: "-backend-option" "-aarch64-global-merge=false"
+// CHECK-NGM-AARCH64: "-backend-option" "-aarch64-enable-global-merge=false"
// RUN: %clang -target armv7-unknown-unknown -### -fsyntax-only %s 2> %t \
// RUN: -mglobal-merge
@@ -26,7 +26,7 @@
// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
// CHECK-GM-ARM: "-backend-option" "-arm-global-merge=true"
-// CHECK-GM-AARCH64: "-backend-option" "-aarch64-global-merge=true"
+// CHECK-GM-AARCH64: "-backend-option" "-aarch64-enable-global-merge=true"
// RUN: %clang -target armv7-unknown-unknown -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
diff --git a/test/Driver/mingw.cpp b/test/Driver/mingw.cpp
index c939c7a33b18..4e25c1dfa0fb 100644
--- a/test/Driver/mingw.cpp
+++ b/test/Driver/mingw.cpp
@@ -7,8 +7,6 @@
// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++"
// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}mingw32"
// CHECK_MINGW_ORG_TREE: "{{.*}}{{/|\\\\}}Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
-// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include"
-// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}mingw32{{/|\\\\}}4.8.1{{/|\\\\}}include-fixed"
// CHECK_MINGW_ORG_TREE: "{{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}mingw32{{/|\\\\}}include"
// CHECK_MINGW_ORG_TREE: {{.*}}/Inputs/mingw_mingw_org_tree/mingw{{/|\\\\}}include
@@ -17,8 +15,6 @@
// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++"
// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}i686-w64-mingw32"
// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
-// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.1{{/|\\\\}}include"
-// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.1{{/|\\\\}}include-fixed"
// CHECK_MINGW_BUILDS_TREE: "{{.*}}/Inputs/mingw_mingw_builds_tree/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
@@ -26,8 +22,6 @@
// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64{{/|\\\\}}mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2"
// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2{{/|\\\\}}i686-w64-mingw32"
// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.9.2{{/|\\\\}}backward"
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.2{{/|\\\\}}include"
-// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}4.9.2{{/|\\\\}}include-fixed"
// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
// CHECK_MINGW_MSYS_TREE: "{{.*}}/Inputs/mingw_msys2_tree/msys64/mingw32{{/|\\\\}}include"
@@ -36,17 +30,13 @@
// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++"
// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}x86_64-w64-mingw32"
// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}backward"
-// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include"
// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}x86_64-w64-mingw32/sys-root/mingw/include"
-// CHECK_MINGW_OPENSUSE_TREE: "{{.*}}/Inputs/mingw_opensuse_tree/usr{{/|\\\\}}lib64{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include-fixed"
// RUN: %clang -target i686-pc-windows-gnu -rtlib=platform -stdlib=libstdc++ -c -### --sysroot=%S/Inputs/mingw_arch_tree/usr %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_ARCH_TREE %s
// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0"
// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0{{/|\\\\}}i686-w64-mingw32"
// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}5.1.0{{/|\\\\}}backward"
-// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include"
-// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}5.1.0{{/|\\\\}}include-fixed"
// CHECK_MINGW_ARCH_TREE: "{{.*}}/Inputs/mingw_arch_tree/usr{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include"
@@ -54,6 +44,4 @@
// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8"
// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8{{/|\\\\}}x86_64-w64-mingw32"
// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}4.8{{/|\\\\}}backward"
-// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}4.8{{/|\\\\}}include"
-// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}4.8{{/|\\\\}}include-fixed"
// CHECK_MINGW_UBUNTU_TREE: "{{.*}}/Inputs/mingw_ubuntu_tree/usr{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}include"
diff --git a/test/Driver/mips-as.c b/test/Driver/mips-as.c
index 4d956208f064..560b5952db53 100644
--- a/test/Driver/mips-as.c
+++ b/test/Driver/mips-as.c
@@ -21,17 +21,32 @@
// MIPS32R2-DEF-EL-AS: as{{(.exe)?}}" "-march" "mips32r2" "-mabi" "32" "-mno-shared" "-call_nonpic" "-EL"
//
// RUN: %clang -target mips64-linux-gnu -### \
-// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: -no-integrated-as -fno-pic -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS64R2-EB-AS %s
-// MIPS64R2-EB-AS: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS64R2-EB-AS: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-EB"
//
-// RUN: %clang -target mips64el-linux-gnu -### \
+// RUN: %clang -target mips64-linux-gnu -### \
// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64R2-EB-AS-PIC %s
+// MIPS64R2-EB-AS-PIC: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-EB" "-KPIC"
+//
+// RUN: %clang -target mips64el-linux-gnu -### \
+// RUN: -no-integrated-as -c -fno-pic %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS64R2-DEF-EL-AS %s
-// MIPS64R2-DEF-EL-AS: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-KPIC" "-EL"
+// MIPS64R2-DEF-EL-AS: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-EL"
+//
+// RUN: %clang -target mips64el-linux-gnu -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64R2-DEF-EL-AS-PIC %s
+// MIPS64R2-DEF-EL-AS-PIC: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-EL" "-KPIC"
//
// RUN: %clang -target mips64-linux-gnu -mabi=n32 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-N32-PIC %s
+// MIPS-N32-PIC: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "n32" "-call_nonpic" "-EB" "-KPIC"
+//
+// RUN: %clang -target mips64-linux-gnu -mabi=n32 -### \
+// RUN: -no-integrated-as -c %s -fno-pic 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-N32 %s
// MIPS-N32: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "n32" "-mno-shared" "-call_nonpic" "-EB"
//
@@ -45,8 +60,13 @@
//
// RUN: %clang -target mips64el-linux-gnu -mabi=64 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64R2-EL-AS-PIC %s
+// MIPS64R2-EL-AS-PIC: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-EL" "-KPIC"
+//
+// RUN: %clang -target mips64el-linux-gnu -mabi=64 -### \
+// RUN: -no-integrated-as -c %s -fno-pic 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS64R2-EL-AS %s
-// MIPS64R2-EL-AS: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-KPIC" "-EL"
+// MIPS64R2-EL-AS: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-EL"
//
// RUN: %clang -target mips-linux-gnu -march=mips32r2 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -60,8 +80,13 @@
//
// RUN: %clang -target mips64-linux-gnu -march=octeon -### \
// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-OCTEON-PIC %s
+// MIPS-OCTEON-PIC: as{{(.exe)?}}" "-march" "octeon" "-mabi" "64" "-EB" "-KPIC"
+//
+// RUN: %clang -target mips64-linux-gnu -march=octeon -### \
+// RUN: -no-integrated-as -c %s -fno-pic 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-OCTEON %s
-// MIPS-OCTEON: as{{(.exe)?}}" "-march" "octeon" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-OCTEON: as{{(.exe)?}}" "-march" "octeon" "-mabi" "64" "-mno-shared" "-EB"
//
// RUN: %clang -target mips-linux-gnu -mips1 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -115,28 +140,48 @@
//
// RUN: %clang -target mips64-linux-gnu -mips64 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64-PIC %s
+// MIPS-ALIAS-64-PIC: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EB" "-KPIC"
+//
+// RUN: %clang -target mips64-linux-gnu -mips64 -### \
+// RUN: -no-integrated-as -c -fno-pic %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64 %s
-// MIPS-ALIAS-64: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-ALIAS-64: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-mno-shared" "-EB"
//
// RUN: %clang -target mips64-linux-gnu -mips64r2 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
-// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R2 %s
-// MIPS-ALIAS-64R2: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R2-PIC %s
+// MIPS-ALIAS-64R2-PIC: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-EB" "-KPIC"
//
// RUN: %clang -target mips64-linux-gnu -mips64r3 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R3-PIC %s
+// MIPS-ALIAS-64R3-PIC: as{{(.exe)?}}" "-march" "mips64r3" "-mabi" "64" "-EB" "-KPIC"
+//
+// RUN: %clang -target mips64-linux-gnu -mips64r3 -### \
+// RUN: -no-integrated-as -c %s -fno-pic 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R3 %s
-// MIPS-ALIAS-64R3: as{{(.exe)?}}" "-march" "mips64r3" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-ALIAS-64R3: as{{(.exe)?}}" "-march" "mips64r3" "-mabi" "64" "-mno-shared" "-EB"
//
// RUN: %clang -target mips64-linux-gnu -mips64r5 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R5-PIC %s
+// MIPS-ALIAS-64R5-PIC: as{{(.exe)?}}" "-march" "mips64r5" "-mabi" "64" "-EB" "-KPIC"
+//
+// RUN: %clang -target mips64-linux-gnu -mips64r5 -### \
+// RUN: -no-integrated-as -c %s -fno-pic 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R5 %s
-// MIPS-ALIAS-64R5: as{{(.exe)?}}" "-march" "mips64r5" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-ALIAS-64R5: as{{(.exe)?}}" "-march" "mips64r5" "-mabi" "64" "-mno-shared" "-EB"
//
// RUN: %clang -target mips64-linux-gnu -mips64r6 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R6-PIC %s
+// MIPS-ALIAS-64R6-PIC: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-EB" "-KPIC"
+//
+// RUN: %clang -target mips64-linux-gnu -mips64r6 -### \
+// RUN: -no-integrated-as -c %s -fno-pic 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R6 %s
-// MIPS-ALIAS-64R6: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS-ALIAS-64R6: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-mno-shared" "-EB"
//
// RUN: %clang -target mips-linux-gnu -mno-mips16 -mips16 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -234,15 +279,15 @@
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips3 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS3-EB-AS %s
-// MIPS3-EB-AS: as{{(.exe)?}}" "-march" "mips3" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS3-EB-AS: as{{(.exe)?}}" "-march" "mips3" "-mabi" "64" "-EB" "-KPIC"
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips4 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS4-EB-AS %s
-// MIPS4-EB-AS: as{{(.exe)?}}" "-march" "mips4" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS4-EB-AS: as{{(.exe)?}}" "-march" "mips4" "-mabi" "64" "-EB" "-KPIC"
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips5 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS5-EB-AS %s
-// MIPS5-EB-AS: as{{(.exe)?}}" "-march" "mips5" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS5-EB-AS: as{{(.exe)?}}" "-march" "mips5" "-mabi" "64" "-EB" "-KPIC"
//
// RUN: %clang -target mips-linux-gnu -### -no-integrated-as -c %s -mcpu=mips32 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS32-EB-AS %s
@@ -256,11 +301,11 @@
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips64 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS64-EB-AS %s
-// MIPS64-EB-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS64-EB-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EB" "-KPIC"
//
// RUN: %clang -target mips64-linux-gnu -### -no-integrated-as -c %s -mcpu=mips64r6 \
// RUN: 2>&1 | FileCheck -check-prefix=MIPS64R6-EB-AS %s
-// MIPS64R6-EB-AS: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-mno-shared" "-KPIC" "-EB"
+// MIPS64R6-EB-AS: as{{(.exe)?}}" "-march" "mips64r6" "-mabi" "64" "-EB" "-KPIC"
//
// RUN: %clang -target mips-linux-gnu -### -no-integrated-as -msoft-float -mhard-float -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=HARDFLOAT --implicit-check-not=-msoft-float %s
diff --git a/test/Driver/msc-version.c b/test/Driver/msc-version.c
index 7e71b9cac8ea..ec87e4d41eb4 100644
--- a/test/Driver/msc-version.c
+++ b/test/Driver/msc-version.c
@@ -63,4 +63,4 @@
// CHECK-MS-EXTENSIONS: _MSC_BUILD 1
// CHECK-MS-EXTENSIONS: _MSC_FULL_VER {{.+}}
-// CHECK-MS-EXTENSIONS: _MSC_VER {{..}}00
+// CHECK-MS-EXTENSIONS: _MSC_VER {{....}}
diff --git a/test/Driver/no-arc-exception-silence.m b/test/Driver/no-arc-exception-silence.m
new file mode 100644
index 000000000000..c16b2206008e
--- /dev/null
+++ b/test/Driver/no-arc-exception-silence.m
@@ -0,0 +1,2 @@
+// RUN: %clang -Werror -fobjc-arc -fobjc-arc-exceptions -fno-objc-arc -Xclang -verify -c -o /dev/null %s
+// expected-no-diagnostics
diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c
index 587c31ded0a7..b4e2796c5d24 100644
--- a/test/Driver/openbsd.c
+++ b/test/Driver/openbsd.c
@@ -3,6 +3,12 @@
// CHECK-LD: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
// CHECK-LD: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+// Check for --eh-frame-hdr being passed with static linking
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -static %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD-STATIC-EH %s
+// CHECK-LD-STATIC-EH: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
+// CHECK-LD-STATIC-EH: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bstatic" "-o" "a.out" "{{.*}}rcrt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+
// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -pg -pthread %s -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PG %s
// CHECK-PG: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
@@ -90,3 +96,8 @@
// CHECK-STATIC-PIE: "{{.*}}rcrt0.o"
// CHECK-STATIC-PIE-NOT: "-nopie"
// CHECK-NOPIE: "-nopie" "{{.*}}crt0.o"
+
+// Check ARM float ABI
+// RUN: %clang -target arm-unknown-openbsd -### -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ARM-FLOAT-ABI %s
+// CHECK-ARM-FLOAT-ABI: "-mfloat-abi" "soft"
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
index 9f9d09c54cf0..61d752094f6e 100644
--- a/test/Driver/pic.c
+++ b/test/Driver/pic.c
@@ -227,6 +227,10 @@
// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
// RUN: %clang -c %s -target i386-pc-openbsd -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
+// RUN: %clang -c %s -target aarch64-unknown-openbsd -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
+// RUN: %clang -c %s -target arm-unknown-openbsd -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
// RUN: %clang -c %s -target mips64-unknown-openbsd -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
// RUN: %clang -c %s -target mips64el-unknown-openbsd -### 2>&1 \
diff --git a/test/Driver/ppc-features.cpp b/test/Driver/ppc-features.cpp
index e32a51a8337d..f37af0918d9e 100644
--- a/test/Driver/ppc-features.cpp
+++ b/test/Driver/ppc-features.cpp
@@ -1,17 +1,3 @@
-// Check that we error when -faltivec is specified on non-ppc platforms.
-
-// RUN: %clang -target powerpc-unk-unk -faltivec -fsyntax-only %s
-// RUN: %clang -target powerpc64-linux-gnu -faltivec -fsyntax-only %s
-// RUN: %clang -target powerpc64-linux-gnu -maltivec -fsyntax-only %s
-
-// RUN: not %clang -target i386-pc-win32 -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: not %clang -target x86_64-unknown-freebsd -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: not %clang -target armv6-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: not %clang -target armv7-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: not %clang -target mips-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: not %clang -target mips64-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: not %clang -target sparc-unknown-solaris -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-
// check -msoft-float option for ppc32
// RUN: %clang -target powerpc-unknown-linux-gnu %s -msoft-float -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-SOFTFLOAT %s
// CHECK-SOFTFLOAT: "-target-feature" "-hard-float"
@@ -56,57 +42,54 @@
// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -mfloat-abi=soft -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-FLOATABISOFT64le %s
// CHECK-FLOATABISOFT64le: "-target-feature" "-hard-float"
-// CHECK: invalid argument '-faltivec' only allowed with 'ppc/ppc64/ppc64le'
+// Check that -mno-altivec correctly disables the altivec target feature on powerpc.
-// Check that -fno-altivec and -mno-altivec correctly disable the altivec
-// target feature on powerpc.
-
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-1 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-1 %s
// CHECK-1: "-target-feature" "-altivec"
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-2 %s
// CHECK-2: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -faltivec -mno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-3 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -maltivec -mno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-3 %s
// CHECK-3: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -maltivec -fno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-4 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -maltivec -mno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-4 %s
// CHECK-4: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -faltivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-5 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -maltivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-5 %s
// CHECK-5-NOT: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -maltivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-6 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -maltivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-6 %s
// CHECK-6-NOT: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=7400 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-7 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=7400 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-7 %s
// CHECK-7: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=g4 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-8 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=g4 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-8 %s
// CHECK-8: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=7450 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-9 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=7450 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-9 %s
// CHECK-9: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=g4+ -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-10 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=g4+ -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-10 %s
// CHECK-10: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=970 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-11 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=970 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-11 %s
// CHECK-11: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=g5 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-12 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=g5 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-12 %s
// CHECK-12: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=pwr6 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-13 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=pwr6 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-13 %s
// CHECK-13: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=pwr7 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-14 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=pwr7 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-14 %s
// CHECK-14: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=pwr8 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-15 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=pwr8 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-15 %s
// CHECK-15: "-target-feature" "-altivec"
-// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=ppc64 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-16 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -mcpu=ppc64 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-16 %s
// CHECK-16: "-target-feature" "-altivec"
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-qpx -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOQPX %s
@@ -151,6 +134,12 @@
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-vsx -mvsx -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-VSX %s
// CHECK-VSX: "-target-feature" "+vsx"
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-htm -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOHTM %s
+// CHECK-NOHTM: "-target-feature" "-htm"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-htm -mhtm -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-HTM %s
+// CHECK-HTM: "-target-feature" "+htm"
+
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-power8-vector -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOP8VECTOR %s
// CHECK-NOP8VECTOR: "-target-feature" "-power8-vector"
diff --git a/test/Driver/r600-mcpu.cl b/test/Driver/r600-mcpu.cl
index 325e57174c33..b99cac3bd7d8 100644
--- a/test/Driver/r600-mcpu.cl
+++ b/test/Driver/r600-mcpu.cl
@@ -40,6 +40,8 @@ t// Check that -mcpu works for all supported GPUs
// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=carrizo %s -o - 2>&1 | FileCheck --check-prefix=CARRIZO-CHECK %s
// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=fiji %s -o - 2>&1 | FileCheck --check-prefix=FIJI-CHECK %s
// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=stoney %s -o - 2>&1 | FileCheck --check-prefix=STONEY-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx900 %s -o - 2>&1 | FileCheck --check-prefix=GFX900-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx901 %s -o - 2>&1 | FileCheck --check-prefix=GFX901-CHECK %s
// R600-CHECK: "-target-cpu" "r600"
// RS880-CHECK: "-target-cpu" "rs880"
@@ -70,3 +72,5 @@ t// Check that -mcpu works for all supported GPUs
// CARRIZO-CHECK: "-target-cpu" "carrizo"
// FIJI-CHECK: "-target-cpu" "fiji"
// STONEY-CHECK: "-target-cpu" "stoney"
+// GFX900-CHECK: "-target-cpu" "gfx900"
+// GFX901-CHECK: "-target-cpu" "gfx901"
diff --git a/test/Driver/reloc-model.c b/test/Driver/reloc-model.c
new file mode 100644
index 000000000000..5d08eee89be3
--- /dev/null
+++ b/test/Driver/reloc-model.c
@@ -0,0 +1,4 @@
+// RUN: not %clang -cc1 -mrelocation-model tinkywinky \
+// RUN: -emit-llvm %s 2>&1 | FileCheck -check-prefix CHECK-INVALID %s
+
+// CHECK-INVALID: error: invalid value 'tinkywinky' in '-mrelocation-model tinkywinky'
diff --git a/test/Driver/response-file.c b/test/Driver/response-file.c
index bd336309adf8..a7c5966c98d1 100644
--- a/test/Driver/response-file.c
+++ b/test/Driver/response-file.c
@@ -1,5 +1,3 @@
-// REQUIRES: long_tests
-
// Check that clang is able to process short response files
// Since this is a short response file, clang must not use a response file
// to pass its parameters to other tools. This is only necessary for a large
@@ -11,11 +9,12 @@
// Check that clang is able to process long response files, routing a long
// sequence of arguments to other tools by using response files as well.
-// We generate a 2MB response file to be big enough to surpass any system
-// limit.
+// We generate a 2MB response file to attempt to surpass any system limit.
+// But there's no guarantee that we actually will (the system limit could be
+// *huge*), so just check that invoking cc1 succeeds under these conditions.
+//
// RUN: %clang -E %S/Inputs/gen-response.c | grep DTEST > %t.1.txt
// RUN: %clang -E @%t.1.txt %s -v 2>&1 | FileCheck %s -check-prefix=LONG
-// LONG: Arguments passed via response file
// LONG: extern int it_works;
#ifdef TEST
diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c
index c98ce8a0c4c7..c4a6f4377b89 100644
--- a/test/Driver/sanitizer-ld.c
+++ b/test/Driver/sanitizer-ld.c
@@ -416,7 +416,9 @@
//
// CHECK-SAFESTACK-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-SAFESTACK-LINUX-NOT: "-lc"
+// CHECK-SAFESTACK-LINUX-NOT: whole-archive
// CHECK-SAFESTACK-LINUX: libclang_rt.safestack-x86_64.a"
+// CHECK-SAFESTACK-LINUX: "-u" "__safestack_init"
// CHECK-SAFESTACK-LINUX: "-lpthread"
// CHECK-SAFESTACK-LINUX: "-ldl"
diff --git a/test/Driver/unknown-std.S b/test/Driver/unknown-std.S
new file mode 100644
index 000000000000..ecb6a9e92faf
--- /dev/null
+++ b/test/Driver/unknown-std.S
@@ -0,0 +1,2 @@
+// RUN: %clang -std=c++11 %s -E -o /dev/null 2>&1 | FileCheck %s --allow-empty
+// CHECK-NOT: error
diff --git a/test/Driver/unknown-std.c b/test/Driver/unknown-std.c
new file mode 100644
index 000000000000..ba3035fd4564
--- /dev/null
+++ b/test/Driver/unknown-std.c
@@ -0,0 +1,34 @@
+// This file checks output given when processing C/ObjC files.
+// When user selects invalid language standard
+// print out supported values with short description.
+
+// RUN: not %clang %s -std=foobar -c 2>&1 | \
+// RUN: FileCheck --match-full-lines %s
+
+// CHECK: error: invalid value 'foobar' in '-std=foobar'
+// CHECK-NEXT: note: use 'c89' for 'ISO C 1990' standard
+// CHECK-NEXT: note: use 'c90' for 'ISO C 1990' standard
+// CHECK-NEXT: note: use 'iso9899:1990' for 'ISO C 1990' standard
+// CHECK-NEXT: note: use 'iso9899:199409' for 'ISO C 1990 with amendment 1' standard
+// CHECK-NEXT: note: use 'gnu89' for 'ISO C 1990 with GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu90' for 'ISO C 1990 with GNU extensions' standard
+// CHECK-NEXT: note: use 'c99' for 'ISO C 1999' standard
+// CHECK-NEXT: note: use 'c9x' for 'ISO C 1999' standard
+// CHECK-NEXT: note: use 'iso9899:1999' for 'ISO C 1999' standard
+// CHECK-NEXT: note: use 'iso9899:199x' for 'ISO C 1999' standard
+// CHECK-NEXT: note: use 'gnu99' for 'ISO C 1999 with GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu9x' for 'ISO C 1999 with GNU extensions' standard
+// CHECK-NEXT: note: use 'c11' for 'ISO C 2011' standard
+// CHECK-NEXT: note: use 'c1x' for 'ISO C 2011' standard
+// CHECK-NEXT: note: use 'iso9899:2011' for 'ISO C 2011' standard
+// CHECK-NEXT: note: use 'iso9899:201x' for 'ISO C 2011' standard
+// CHECK-NEXT: note: use 'gnu11' for 'ISO C 2011 with GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu1x' for 'ISO C 2011 with GNU extensions' standard
+// CHECK-NEXT: note: use 'cl' for 'OpenCL 1.0' standard
+// CHECK-NEXT: note: use 'cl1.1' for 'OpenCL 1.1' standard
+// CHECK-NEXT: note: use 'cl1.2' for 'OpenCL 1.2' standard
+// CHECK-NEXT: note: use 'cl2.0' for 'OpenCL 2.0' standard
+
+// Make sure that no other output is present.
+// CHECK-NOT: {{^.+$}}
+
diff --git a/test/Driver/unknown-std.cl b/test/Driver/unknown-std.cl
new file mode 100644
index 000000000000..b87a8c881ce5
--- /dev/null
+++ b/test/Driver/unknown-std.cl
@@ -0,0 +1,16 @@
+// This file checks output given when processing OpenCL files.
+// When user selects invalid language standard
+// print out supported values with short description.
+
+// RUN: not %clang %s -std=foobar -c 2>&1 | \
+// RUN: FileCheck --match-full-lines %s
+
+// CHECK: error: invalid value 'foobar' in '-std=foobar'
+// CHECK-NEXT: note: use 'cl' for 'OpenCL 1.0' standard
+// CHECK-NEXT: note: use 'cl1.1' for 'OpenCL 1.1' standard
+// CHECK-NEXT: note: use 'cl1.2' for 'OpenCL 1.2' standard
+// CHECK-NEXT: note: use 'cl2.0' for 'OpenCL 2.0' standard
+
+// Make sure that no other output is present.
+// CHECK-NOT: {{^.+$}}
+
diff --git a/test/Driver/unknown-std.cpp b/test/Driver/unknown-std.cpp
new file mode 100644
index 000000000000..faeb2cba8a4b
--- /dev/null
+++ b/test/Driver/unknown-std.cpp
@@ -0,0 +1,26 @@
+// This file checks output given when processing C++/ObjC++ files.
+// When user selects invalid language standard
+// print out supported values with short description.
+
+// RUN: not %clang %s -std=foobar -c 2>&1 | \
+// RUN: FileCheck --match-full-lines %s
+
+// CHECK: error: invalid value 'foobar' in '-std=foobar'
+// CHECK-NEXT: note: use 'c++98' for 'ISO C++ 1998 with amendments' standard
+// CHECK-NEXT: note: use 'c++03' for 'ISO C++ 1998 with amendments' standard
+// CHECK-NEXT: note: use 'gnu++98' for 'ISO C++ 1998 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'c++0x' for 'ISO C++ 2011 with amendments' standard
+// CHECK-NEXT: note: use 'c++11' for 'ISO C++ 2011 with amendments' standard
+// CHECK-NEXT: note: use 'gnu++0x' for 'ISO C++ 2011 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu++11' for 'ISO C++ 2011 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'c++1y' for 'ISO C++ 2014 with amendments' standard
+// CHECK-NEXT: note: use 'c++14' for 'ISO C++ 2014 with amendments' standard
+// CHECK-NEXT: note: use 'gnu++1y' for 'ISO C++ 2014 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu++14' for 'ISO C++ 2014 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'c++1z' for 'Working draft for ISO C++ 2017' standard
+// CHECK-NEXT: note: use 'gnu++1z' for 'Working draft for ISO C++ 2017 with GNU extensions' standard
+// CHECK-NEXT: note: use 'cuda' for 'NVIDIA CUDA(tm)' standard
+
+// Make sure that no other output is present.
+// CHECK-NOT: {{^.+$}}
+
diff --git a/test/Driver/unsupported-faltivec.c b/test/Driver/unsupported-faltivec.c
new file mode 100644
index 000000000000..f6a55bcd39f8
--- /dev/null
+++ b/test/Driver/unsupported-faltivec.c
@@ -0,0 +1,10 @@
+// Tests that clang does not crash with invalid architectures in target triples.
+//
+// RUN: not %clang -target powerpc64le-linux-gnu -faltivec -o %t.o %s 2> %t.err
+// RUN: FileCheck --input-file=%t.err --check-prefix=CHECK-NOFALTIVEC %s
+// CHECK-NOFALTIVEC: error: the clang compiler does not support 'faltivec', please use -maltivec and include altivec.h explicitly
+//
+// RUN: not %clang -target powerpc64le-linux-gnu -fno-altivec -o %t.o %s 2> %t.err
+// RUN: FileCheck --input-file=%t.err --check-prefix=CHECK-NOFNOALTIVEC %s
+// CHECK-NOFNOALTIVEC: error: the clang compiler does not support 'fno-altivec', please use -mno-altivec
+
diff --git a/test/Driver/windows-cross.c b/test/Driver/windows-cross.c
index 5a2fe52b099e..de6fcba7a504 100644
--- a/test/Driver/windows-cross.c
+++ b/test/Driver/windows-cross.c
@@ -1,27 +1,27 @@
// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -stdlib=libstdc++ -rtlib=platform -o /dev/null %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-BASIC
-// CHECK-BASIC: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// CHECK-BASIC: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
// RUN: %clang -### -target armv7-windows-itanium --sysroot %s/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -rtlib=compiler-rt -stdlib=libstdc++ -o /dev/null %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-RTLIB
-// CHECK-RTLIB: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+// CHECK-RTLIB: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-C-LIBCXX
-// CHECK-C-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+// CHECK-C-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
// RUN: %clangxx -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-LIBCXX
-// CHECK-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "{{.*}}.o" "-lc++" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+// CHECK-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}.o" "-lc++" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -shared -rtlib=compiler-rt -stdlib=libc++ -o shared.dll %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-SHARED
-// CHECK-SHARED: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definition" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbeginS.obj" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
+// CHECK-SHARED: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definition" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
// RUN: %clang -### -target armv7-windows-itanium --sysroot %s/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -o shared.dll %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-NOSTARTFILES
diff --git a/test/Driver/x86-target-features.c b/test/Driver/x86-target-features.c
index ce35b2cfd0dc..dc32f6c470b4 100644
--- a/test/Driver/x86-target-features.c
+++ b/test/Driver/x86-target-features.c
@@ -49,3 +49,38 @@
// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-xsave -mno-xsaveopt -mno-xsavec -mno-xsaves %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-XSAVE %s
// XSAVE: "-target-feature" "+xsave" "-target-feature" "+xsaveopt" "-target-feature" "+xsavec" "-target-feature" "+xsaves"
// NO-XSAVE: "-target-feature" "-xsave" "-target-feature" "-xsaveopt" "-target-feature" "-xsavec" "-target-feature" "-xsaves"
+
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mclflushopt %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CLFLUSHOPT %s
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-clflushopt %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-CLFLUSHOPT %s
+// CLFLUSHOPT: "-target-feature" "+clflushopt"
+// NO-CLFLUSHOPT: "-target-feature" "-clflushopt"
+
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mclwb %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CLWB %s
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-clwb %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-CLWB %s
+// CLWB: "-target-feature" "+clwb"
+// NO-CLWB: "-target-feature" "-clwb"
+
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mmovbe %s -### -o %t.o 2>&1 | FileCheck -check-prefix=MOVBE %s
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-movbe %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-MOVBE %s
+// MOVBE: "-target-feature" "+movbe"
+// NO-MOVBE: "-target-feature" "-movbe"
+
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mmpx %s -### -o %t.o 2>&1 | FileCheck -check-prefix=MPX %s
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-mpx %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-MPX %s
+// MPX: "-target-feature" "+mpx"
+// NO-MPX: "-target-feature" "-mpx"
+
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -msgx %s -### -o %t.o 2>&1 | FileCheck -check-prefix=SGX %s
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-sgx %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-SGX %s
+// SGX: "-target-feature" "+sgx"
+// NO-SGX: "-target-feature" "-sgx"
+
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mprefetchwt1 %s -### -o %t.o 2>&1 | FileCheck -check-prefix=PREFETCHWT1 %s
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-prefetchwt1 %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-PREFETCHWT1 %s
+// PREFETCHWT1: "-target-feature" "+prefetchwt1"
+// NO-PREFETCHWT1: "-target-feature" "-prefetchwt1"
+
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mclzero %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CLZERO %s
+// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-clzero %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-CLZERO %s
+// CLZERO: "-target-feature" "+clzero"
+// NO-CLZERO: "-target-feature" "-clzero"
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index c43aac98623c..0b7fc626ff8a 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -409,3 +409,14 @@ const const_zero_init czi; // expected-error {{default initialization of an obje
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"{}"
int use_czi = czi.a;
+namespace dotPointerDestructor {
+
+struct Bar {
+ ~Bar();
+};
+
+void bar(Bar *o) {
+ o.~Bar(); // expected-error {{member reference type 'dotPointerDestructor::Bar *' is a pointer; did you mean to use '->'}}
+} // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:5}:"->"
+
+}
diff --git a/test/FixIt/no-fixit.cpp b/test/FixIt/no-fixit.cpp
index 7e8e1fbbb07b..2dad28d3579b 100644
--- a/test/FixIt/no-fixit.cpp
+++ b/test/FixIt/no-fixit.cpp
@@ -11,3 +11,15 @@ struct {
(void)&i;
}
} x;
+
+namespace dotPointerDestructor {
+
+struct Bar {
+ ~Bar() = delete;
+};
+
+void bar(Bar *o) {
+ o.~Bar(); // no fixit
+}
+
+}
diff --git a/test/Format/inplace.cpp b/test/Format/inplace.cpp
new file mode 100644
index 000000000000..175a8b65d7fd
--- /dev/null
+++ b/test/Format/inplace.cpp
@@ -0,0 +1,264 @@
+// Regression test to check that clang-format does not leave behind temporary
+// files on Windows when doing in-place formatting.
+// RUN: rm -rf %t.dir
+// RUN: mkdir %t.dir
+// RUN: cp %s %t.dir/inplace.cpp
+// RUN: clang-format -style=LLVM -i %t.dir/inplace.cpp
+// RUN: ls %t.dir > %t.dir/files.txt
+// RUN: FileCheck -strict-whitespace -input-file=%t.dir/files.txt %s
+
+// CHECK-NOT: RF{{.*}}.TMP
+
+// The file needs to be larger than 16kiB so that Windows creates a real file
+// mapping object for it.
+ int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
+int this_is_my_int_there_are_many_like_it_but_this_one_is_mine;
diff --git a/test/Format/style-on-command-line.cpp b/test/Format/style-on-command-line.cpp
index 08da60a988d1..b2724353da13 100644
--- a/test/Format/style-on-command-line.cpp
+++ b/test/Format/style-on-command-line.cpp
@@ -1,30 +1,37 @@
// RUN: clang-format -style="{BasedOnStyle: Google, IndentWidth: 8}" %s | FileCheck -strict-whitespace -check-prefix=CHECK1 %s
// RUN: clang-format -style="{BasedOnStyle: LLVM, IndentWidth: 7}" %s | FileCheck -strict-whitespace -check-prefix=CHECK2 %s
-// RUN: clang-format -style="{BasedOnStyle: invalid, IndentWidth: 7}" -fallback-style=LLVM %s 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK3 %s
-// RUN: clang-format -style="{lsjd}" %s -fallback-style=LLVM 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK4 %s
+// RUN: not clang-format -style="{BasedOnStyle: invalid, IndentWidth: 7}" -fallback-style=LLVM %s 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK3 %s
+// RUN: not clang-format -style="{lsjd}" %s -fallback-style=LLVM 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK4 %s
// RUN: printf "BasedOnStyle: google\nIndentWidth: 5\n" > %T/.clang-format
// RUN: clang-format -style=file -assume-filename=%T/foo.cpp < %s | FileCheck -strict-whitespace -check-prefix=CHECK5 %s
// RUN: printf "\n" > %T/.clang-format
-// RUN: clang-format -style=file -fallback-style=webkit -assume-filename=%T/foo.cpp < %s 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK6 %s
+// RUN: not clang-format -style=file -fallback-style=webkit -assume-filename=%T/foo.cpp < %s 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK6 %s
// RUN: rm %T/.clang-format
// RUN: printf "BasedOnStyle: google\nIndentWidth: 6\n" > %T/_clang-format
// RUN: clang-format -style=file -assume-filename=%T/foo.cpp < %s | FileCheck -strict-whitespace -check-prefix=CHECK7 %s
// RUN: clang-format -style="{BasedOnStyle: LLVM, PointerBindsToType: true}" %s | FileCheck -strict-whitespace -check-prefix=CHECK8 %s
// RUN: clang-format -style="{BasedOnStyle: WebKit, PointerBindsToType: false}" %s | FileCheck -strict-whitespace -check-prefix=CHECK9 %s
+
+// Fallback style tests
+// Test config file with no based style, and fallback style "none", formatting is applied
+// RUN: printf "IndentWidth: 6\n" > %T/_clang-format
+// RUN: clang-format -style=file -fallback-style=none -assume-filename=%T/foo.cpp < %s 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK10 %s
+// Test yaml with no based style, and fallback style "none", LLVM formatting applied
+// RUN: clang-format -style="{IndentWidth: 7}" -fallback-style=none %s | FileCheck -strict-whitespace -check-prefix=CHECK11 %s
+
void f() {
// CHECK1: {{^ int\* i;$}}
// CHECK2: {{^ int \*i;$}}
// CHECK3: Unknown value for BasedOnStyle: invalid
-// CHECK3: Error parsing -style: {{I|i}}nvalid argument, using LLVM style
-// CHECK3: {{^ int \*i;$}}
-// CHECK4: Error parsing -style: {{I|i}}nvalid argument, using LLVM style
-// CHECK4: {{^ int \*i;$}}
+// CHECK3: Error parsing -style: {{I|i}}nvalid argument
+// CHECK4: Error parsing -style: {{I|i}}nvalid argument
// CHECK5: {{^ int\* i;$}}
// CHECK6: {{^Error reading .*\.clang-format: (I|i)nvalid argument}}
-// CHECK6: {{^ int\* i;$}}
// CHECK7: {{^ int\* i;$}}
// CHECK8: {{^ int\* i;$}}
// CHECK9: {{^ int \*i;$}}
+// CHECK10: {{^ int \*i;$}}
+// CHECK11: {{^ int \*i;$}}
int*i;
int j;
}
diff --git a/test/Frontend/aarch64-target-cpu.c b/test/Frontend/aarch64-target-cpu.c
index 90546472caf1..c80369402eaa 100644
--- a/test/Frontend/aarch64-target-cpu.c
+++ b/test/Frontend/aarch64-target-cpu.c
@@ -9,6 +9,6 @@
// RUN: %clang_cc1 -triple aarch64-unknown-unknown -target-cpu exynos-m1 -verify %s
// RUN: %clang_cc1 -triple aarch64-unknown-unknown -target-cpu generic -verify %s
// RUN: %clang_cc1 -triple aarch64-unknown-unknown -target-cpu kryo -verify %s
-// RUN: %clang_cc1 -triple aarch64-unknown-unknown -target-cpu vulcan -verify %s
+// RUN: %clang_cc1 -triple aarch64-unknown-unknown -target-cpu thunderx2t99 -verify %s
//
// expected-no-diagnostics
diff --git a/test/Frontend/gnu-mcount.c b/test/Frontend/gnu-mcount.c
index 690a103ed9ec..508be14f35c9 100644
--- a/test/Frontend/gnu-mcount.c
+++ b/test/Frontend/gnu-mcount.c
@@ -6,11 +6,11 @@
// RUN: %clang -target aarch64-unknown-none-eabi -pg -meabi gnu -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI-MEABI-GNU
// RUN: %clang -target armv7-unknown-linux-gnueabi -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI
// RUN: %clang -target armv7-unknown-linux-gnueabi -meabi gnu -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-MEABI-GNU
-// RUN: %clang -target aarch64-unknown-linux-gnueabi -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI
+// RUN: %clang -target aarch64-unknown-linux-gnueabi -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI-LINUX
// RUN: %clang -target aarch64-unknown-linux-gnueabi -meabi gnu -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI-MEABI-GNU
// RUN: %clang -target armv7-unknown-linux-gnueabihf -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI
// RUN: %clang -target armv7-unknown-linux-gnueabihf -meabi gnu -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-MEABI-GNU
-// RUN: %clang -target aarch64-unknown-linux-gnueabihf -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI
+// RUN: %clang -target aarch64-unknown-linux-gnueabihf -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI-LINUX
// RUN: %clang -target aarch64-unknown-linux-gnueabihf -meabi gnu -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI-MEABI-GNU
// RUN: %clang -target armv7-unknown-freebsd-gnueabihf -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-FREEBSD
// RUN: %clang -target armv7-unknown-freebsd-gnueabihf -meabi gnu -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-FREEBSD
@@ -53,6 +53,7 @@ int f() {
// CHECK-ARM64-EABI: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
// CHECK-ARM64-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01_mcount"{{.*}} }
// CHECK-ARM64-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
+// CHECK-ARM64-EABI-LINUX: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01_mcount"{{.*}} }
// CHECK-ARM-EABI-FREEBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="__mcount"{{.*}} }
// CHECK-ARM-EABI-FREEBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
// CHECK-ARM64-EABI-FREEBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"=".mcount"{{.*}} }
@@ -61,7 +62,7 @@ int f() {
// CHECK-ARM-EABI-NETBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
// CHECK-ARM-EABI-OPENBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="__mcount"{{.*}} }
// CHECK-ARM-EABI-OPENBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
-// CHECK-ARM64-EABI-OPENBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
+// CHECK-ARM64-EABI-OPENBSD: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="__mcount"{{.*}} }
// CHECK-ARM64-EABI-OPENBSD-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
// CHECK-ARM-EABI-MEABI-GNU-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
// CHECK-ARM-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
diff --git a/test/Frontend/iframework.c b/test/Frontend/iframework.c
index 6f801f2437a2..2354553fa094 100644
--- a/test/Frontend/iframework.c
+++ b/test/Frontend/iframework.c
@@ -1,4 +1,5 @@
// RUN: %clang -fsyntax-only -iframework %S/Inputs %s -Xclang -verify
+// RUN: %clang -fsyntax-only -isysroot %S -iframeworkwithsysroot /Inputs %s -Xclang -verify
// expected-no-diagnostics
#include <TestFramework/TestFramework.h>
diff --git a/test/Frontend/objc-bool-is-bool.m b/test/Frontend/objc-bool-is-bool.m
index 464fe2ea8c0c..ee4fb58d5a77 100644
--- a/test/Frontend/objc-bool-is-bool.m
+++ b/test/Frontend/objc-bool-is-bool.m
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -E -dM -triple=armv7k-apple-watchos %s | FileCheck --check-prefix=BOOL %s
// RUN: %clang_cc1 -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=CHAR %s
-// RUN: %clang_cc1 -x c -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=NONE %s
+// RUN: %clang_cc1 -x c -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=CHAR %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=CHAR %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -E -dM -triple=x86_64-apple-darwin16 %s | FileCheck --check-prefix=CHAR %s
// rdar://21170440
@@ -9,5 +11,3 @@
// CHAR: #define __OBJC_BOOL_IS_BOOL 0
// CHAR-NOT: #define __OBJC_BOOL_IS_BOOL 1
-
-// NONE-NOT: __OBJC_BOOL_IS_BOOL
diff --git a/test/Frontend/optimization-remark-with-hotness.c b/test/Frontend/optimization-remark-with-hotness.c
index 4c27e866f4ce..708f5ec8d4bf 100644
--- a/test/Frontend/optimization-remark-with-hotness.c
+++ b/test/Frontend/optimization-remark-with-hotness.c
@@ -4,11 +4,13 @@
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \
// RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \
// RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \
-// RUN: -Rpass-analysis=inline -fdiagnostics-show-hotness -verify
+// RUN: -Rpass-analysis=inline -Rpass-missed=inline \
+// RUN: -fdiagnostics-show-hotness -verify
// The clang version of the previous test.
// RUN: %clang -target x86_64-apple-macosx10.9 %s -c -emit-llvm -o /dev/null \
// RUN: -fprofile-instr-use=%t.profdata -Rpass=inline \
-// RUN: -Rpass-analysis=inline -fdiagnostics-show-hotness -Xclang -verify
+// RUN: -Rpass-analysis=inline -Rpass-missed=inline \
+// RUN: -fdiagnostics-show-hotness -Xclang -verify
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \
// RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \
// RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \
@@ -39,7 +41,7 @@ void bar(int x) {
int main(int argc, const char *argv[]) {
for (int i = 0; i < 30; i++)
- // expected-remark@+1 {{bar should never be inlined}}
+ // expected-remark@+1 {{bar not inlined into main because it should never be inlined}}
bar(argc);
return sum;
}
diff --git a/test/Frontend/optimization-remark.c b/test/Frontend/optimization-remark.c
index 72cad8ff608c..7c02233d6835 100644
--- a/test/Frontend/optimization-remark.c
+++ b/test/Frontend/optimization-remark.c
@@ -42,10 +42,8 @@ float foz(int x, int y) { return x * y; }
// twice.
//
int bar(int j) {
-// expected-remark@+6 {{foz should never be inlined (cost=never)}}
-// expected-remark@+5 {{foz will not be inlined into bar}}
-// expected-remark@+4 {{foz should never be inlined}}
-// expected-remark@+3 {{foz will not be inlined into bar}}
+// expected-remark@+4 {{foz not inlined into bar because it should never be inlined (cost=never)}}
+// expected-remark@+3 {{foz not inlined into bar because it should never be inlined (cost=never)}}
// expected-remark@+2 {{foo should always be inlined}}
// expected-remark@+1 {{foo inlined into bar}}
return foo(j, j - 2) * foz(j - 2, j);
diff --git a/test/Frontend/preprocessed-input.i b/test/Frontend/preprocessed-input.i
new file mode 100644
index 000000000000..9d5867e4ced4
--- /dev/null
+++ b/test/Frontend/preprocessed-input.i
@@ -0,0 +1,10 @@
+# 1 "preprocessed-input.c"
+# 1 "<built-in>" 1
+# 1 "<built-in>" 3
+# 318 "<built-in>" 3
+# 1 "<command line>" 1
+# 1 "<built-in>" 2
+# 1 "preprocessed-input.c" 2
+
+// RUN: %clang -emit-llvm -S -o - %s | FileCheck %s
+// CHECK: source_filename = "preprocessed-input.c"{{$}}
diff --git a/test/Headers/Inputs/usr/include/math.h b/test/Headers/Inputs/usr/include/math.h
new file mode 100644
index 000000000000..4171d4febc63
--- /dev/null
+++ b/test/Headers/Inputs/usr/include/math.h
@@ -0,0 +1 @@
+// math.h
diff --git a/test/Headers/Inputs/usr/include/tgmath.h b/test/Headers/Inputs/usr/include/tgmath.h
new file mode 100644
index 000000000000..897962d9e16e
--- /dev/null
+++ b/test/Headers/Inputs/usr/include/tgmath.h
@@ -0,0 +1,4 @@
+#ifndef SYS_TGMATH_H
+#define SYS_TGMATH_H
+
+#endif /* SYS_TGMATH_H */
diff --git a/test/Headers/altivec-header.c b/test/Headers/altivec-header.c
index 0ea9e2b52d4c..733ab5002a92 100644
--- a/test/Headers/altivec-header.c
+++ b/test/Headers/altivec-header.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -emit-llvm -fno-lax-vector-conversions -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -emit-llvm -x c++ -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -target-feature +altivec -ffreestanding -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -target-feature +altivec -ffreestanding -emit-llvm -fno-lax-vector-conversions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -target-feature +altivec -ffreestanding -emit-llvm -x c++ -o - %s | FileCheck %s
#include <altivec.h>
@@ -9,4 +9,4 @@
// CHECK: target triple = "powerpc64-
// CHECK-NEXT: {{^$}}
-// CHECK-NEXT: llvm.ident
+// CHECK-NEXT: {{llvm\..*}}
diff --git a/test/Headers/altivec-intrin.c b/test/Headers/altivec-intrin.c
index 7e6ea0098740..c71b48da040d 100644
--- a/test/Headers/altivec-intrin.c
+++ b/test/Headers/altivec-intrin.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -target-cpu power8 \
-// RUN: -faltivec -verify %s
+// RUN: -target-feature +altivec -verify %s
// Test special behavior of Altivec intrinsics in this file.
diff --git a/test/Headers/htm-header.c b/test/Headers/htm-header.c
new file mode 100644
index 000000000000..35a14983bee6
--- /dev/null
+++ b/test/Headers/htm-header.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-feature +htm -DHTM_HEADER -ffreestanding -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-feature +htm -DHTM_HEADER -ffreestanding -emit-llvm -x c++ -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-feature +htm -DHTMXL_HEADER -ffreestanding -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-feature +htm -DHTMXL_HEADER -ffreestanding -emit-llvm -x c++ -o - %s | FileCheck %s
+
+#ifdef HTM_HEADER
+#include <htmintrin.h>
+#endif
+
+#ifdef HTMXL_HEADER
+#include <htmxlintrin.h>
+#endif
+
+// Verify that simply including the headers does not generate any code
+// (i.e. all inline routines in the header are marked "static")
+
+// CHECK: target triple = "powerpc64
+// CHECK-NEXT: {{^$}}
+// CHECK-NEXT: {{llvm\..*}}
diff --git a/test/Headers/opencl-c-header.cl b/test/Headers/opencl-c-header.cl
index 457a6193d41a..2c28be19fa67 100644
--- a/test/Headers/opencl-c-header.cl
+++ b/test/Headers/opencl-c-header.cl
@@ -1,16 +1,11 @@
-// RUN: %clang_cc1 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
-
-// CHECK: _Z16convert_char_rtec
-// CHECK-NOT: _Z3ctzc
-// CHECK20: _Z3ctzc
-// CHECK20-NOT: _Z16convert_char_rtec
-// CHECK-MOD: Reading modules
+// RUN: %clang_cc1 -O0 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s| FileCheck %s
+// RUN: %clang_cc1 -O0 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// Test including the default header as a module.
// The module should be compiled only once and loaded from cache afterwards.
// Change the directory mode to read only to make sure no new modules are created.
// Check time report to make sure module is used.
+// Check that some builtins occur in the generated IR when called.
// ===
// Clear current directory.
@@ -30,32 +25,50 @@
// ===
// Compile for OpenCL 2.0 for the first time. The module should change.
-// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -o - -cl-std=CL2.0 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fdisable-module-hash -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK20 --check-prefix=CHECK-MOD %s
+// RUN: %clang_cc1 -triple spir-unknown-unknown -O0 -emit-llvm -o - -cl-std=CL2.0 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fdisable-module-hash -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK20 --check-prefix=CHECK-MOD %s
// RUN: not diff %t/1_0.pcm %t/opencl_c.pcm
// RUN: chmod u-w %t/opencl_c.pcm
// ===
// Compile for OpenCL 2.0 for the second time. The module should not change.
-// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -o - -cl-std=CL2.0 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fdisable-module-hash -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK20 --check-prefix=CHECK-MOD %s
+// RUN: %clang_cc1 -triple spir-unknown-unknown -O0 -emit-llvm -o - -cl-std=CL2.0 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fdisable-module-hash -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK20 --check-prefix=CHECK-MOD %s
// Check cached module works for different OpenCL versions.
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: %clang_cc1 -triple spir64-unknown-unknown -emit-llvm -o - -cl-std=CL1.2 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MOD %s
-// RUN: %clang_cc1 -triple amdgcn--amdhsa -emit-llvm -o - -cl-std=CL2.0 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK20 --check-prefix=CHECK-MOD %s
+// RUN: %clang_cc1 -triple amdgcn--amdhsa -O0 -emit-llvm -o - -cl-std=CL2.0 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK20 --check-prefix=CHECK-MOD %s
// RUN: chmod u-w %t
// RUN: %clang_cc1 -triple spir64-unknown-unknown -emit-llvm -o - -cl-std=CL1.2 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MOD %s
-// RUN: %clang_cc1 -triple amdgcn--amdhsa -emit-llvm -o - -cl-std=CL2.0 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK20 --check-prefix=CHECK-MOD %s
+// RUN: %clang_cc1 -triple amdgcn--amdhsa -O0 -emit-llvm -o - -cl-std=CL2.0 -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ftime-report %s 2>&1 | FileCheck --check-prefix=CHECK20 --check-prefix=CHECK-MOD %s
// RUN: chmod u+w %t
+// Verify that called builtins occur in the generated IR.
+
+// CHECK-NOT: ndrange_t
+// CHECK20: ndrange_t
+// CHECK: _Z16convert_char_rtec
+// CHECK-NOT: _Z3ctzc
+// CHECK20: _Z3ctzc
+// CHECK20-NOT: _Z16convert_char_rtec
char f(char x) {
#if __OPENCL_C_VERSION__ != CL_VERSION_2_0
return convert_char_rte(x);
-#ifdef NO_HEADER
- //expected-warning@-2{{implicit declaration of function 'convert_char_rte' is invalid in C99}}
-#endif //NO_HEADER
#else //__OPENCL_C_VERSION__
+ ndrange_t t;
return ctz(x);
#endif //__OPENCL_C_VERSION__
}
+
+// Verify that a builtin using a write_only image3d_t type is available
+// from OpenCL 2.0 onwards.
+
+// CHECK20: _Z12write_imagef14ocl_image3d_wo
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+void test_image3dwo(write_only image3d_t img) {
+ write_imagef(img, (0), (0.0f));
+}
+#endif //__OPENCL_C_VERSION__
+
+// CHECK-MOD: Reading modules
diff --git a/test/Headers/stdarg-gnuc_va_list.c b/test/Headers/stdarg-gnuc_va_list.c
new file mode 100644
index 000000000000..da9db8ddc20a
--- /dev/null
+++ b/test/Headers/stdarg-gnuc_va_list.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wsystem-headers -std=c99 %s
+// expected-no-diagnostics
+
+// Check that no warnings are emitted from stdarg.h if __gnuc_va_list has
+// previously been defined in another header file.
+typedef __builtin_va_list __va_list;
+typedef __va_list __gnuc_va_list;
+#define __GNUC_VA_LIST
+
+#include <stdarg.h>
diff --git a/test/Headers/tgmath-darwin.c b/test/Headers/tgmath-darwin.c
new file mode 100644
index 000000000000..916605a718ab
--- /dev/null
+++ b/test/Headers/tgmath-darwin.c
@@ -0,0 +1,12 @@
+// REQUIRES: system-darwin
+// RUN: %clang -target x86_64-apple-darwin10 -fsyntax-only -std=c11 -isysroot %S/Inputs %s
+#include <tgmath.h>
+
+// Test the #include_next of tgmath.h works on Darwin.
+#ifndef SYS_TGMATH_H
+ #error "SYS_TGMATH_H not defined"
+#endif
+
+#ifndef __CLANG_TGMATH_H
+ #error "__CLANG_TGMATH_H not defined"
+#endif
diff --git a/test/Import/forward-declared-struct/Inputs/S1.c b/test/Import/forward-declared-struct/Inputs/S1.c
new file mode 100644
index 000000000000..28377c2760ba
--- /dev/null
+++ b/test/Import/forward-declared-struct/Inputs/S1.c
@@ -0,0 +1 @@
+struct S;
diff --git a/test/Import/forward-declared-struct/Inputs/S2.c b/test/Import/forward-declared-struct/Inputs/S2.c
new file mode 100644
index 000000000000..b0876d27df44
--- /dev/null
+++ b/test/Import/forward-declared-struct/Inputs/S2.c
@@ -0,0 +1,3 @@
+struct S {
+ int a;
+};
diff --git a/test/Import/forward-declared-struct/test.c b/test/Import/forward-declared-struct/test.c
new file mode 100644
index 000000000000..7ccdcf9e97d0
--- /dev/null
+++ b/test/Import/forward-declared-struct/test.c
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s
+void expr() {
+ struct S MyS;
+ MyS.a = 3;
+}
diff --git a/test/Import/member-in-struct/Inputs/S.c b/test/Import/member-in-struct/Inputs/S.c
new file mode 100644
index 000000000000..b0876d27df44
--- /dev/null
+++ b/test/Import/member-in-struct/Inputs/S.c
@@ -0,0 +1,3 @@
+struct S {
+ int a;
+};
diff --git a/test/Import/member-in-struct/test.c b/test/Import/member-in-struct/test.c
new file mode 100644
index 000000000000..bde2b60d275f
--- /dev/null
+++ b/test/Import/member-in-struct/test.c
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -import %S/Inputs/S.c -expression %s
+void expr() {
+ struct S MyS;
+ MyS.a = 3;
+}
diff --git a/test/Import/multiple-forward-declarations/Inputs/S1.c b/test/Import/multiple-forward-declarations/Inputs/S1.c
new file mode 100644
index 000000000000..28377c2760ba
--- /dev/null
+++ b/test/Import/multiple-forward-declarations/Inputs/S1.c
@@ -0,0 +1 @@
+struct S;
diff --git a/test/Import/multiple-forward-declarations/Inputs/S2.c b/test/Import/multiple-forward-declarations/Inputs/S2.c
new file mode 100644
index 000000000000..28377c2760ba
--- /dev/null
+++ b/test/Import/multiple-forward-declarations/Inputs/S2.c
@@ -0,0 +1 @@
+struct S;
diff --git a/test/Import/multiple-forward-declarations/test.c b/test/Import/multiple-forward-declarations/test.c
new file mode 100644
index 000000000000..fdaaaf611434
--- /dev/null
+++ b/test/Import/multiple-forward-declarations/test.c
@@ -0,0 +1,4 @@
+// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s
+void expr() {
+ struct S *MySPtr;
+}
diff --git a/test/Import/overloaded-function/Inputs/F1.c b/test/Import/overloaded-function/Inputs/F1.c
new file mode 100644
index 000000000000..fb548b464f2e
--- /dev/null
+++ b/test/Import/overloaded-function/Inputs/F1.c
@@ -0,0 +1 @@
+void f(int arg) { }
diff --git a/test/Import/overloaded-function/Inputs/F2.c b/test/Import/overloaded-function/Inputs/F2.c
new file mode 100644
index 000000000000..937efe54d84e
--- /dev/null
+++ b/test/Import/overloaded-function/Inputs/F2.c
@@ -0,0 +1,4 @@
+struct S { int a; };
+
+void f(const char *arg) { }
+void f(S arg) { }
diff --git a/test/Import/overloaded-function/test.c b/test/Import/overloaded-function/test.c
new file mode 100644
index 000000000000..4f7781bc8e6d
--- /dev/null
+++ b/test/Import/overloaded-function/test.c
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -import %S/Inputs/F1.c -import %S/Inputs/F2.c -expression %s
+void expr() {
+ f(2);
+ f("world");
+ S s;
+ f(s);
+}
diff --git a/test/Import/struct-in-namespace/Inputs/N1.cpp b/test/Import/struct-in-namespace/Inputs/N1.cpp
new file mode 100644
index 000000000000..ddb67a516213
--- /dev/null
+++ b/test/Import/struct-in-namespace/Inputs/N1.cpp
@@ -0,0 +1,11 @@
+namespace N {
+ struct S {
+ int a;
+ };
+}
+
+namespace N {
+ struct T {
+ int b;
+ };
+}
diff --git a/test/Import/struct-in-namespace/Inputs/N2.cpp b/test/Import/struct-in-namespace/Inputs/N2.cpp
new file mode 100644
index 000000000000..ad97d5dd52ea
--- /dev/null
+++ b/test/Import/struct-in-namespace/Inputs/N2.cpp
@@ -0,0 +1,5 @@
+namespace N {
+ struct U {
+ int c;
+ };
+}
diff --git a/test/Import/struct-in-namespace/Inputs/N3.cpp b/test/Import/struct-in-namespace/Inputs/N3.cpp
new file mode 100644
index 000000000000..e0ec41467477
--- /dev/null
+++ b/test/Import/struct-in-namespace/Inputs/N3.cpp
@@ -0,0 +1,5 @@
+namespace M {
+ struct V {
+ int d;
+ };
+}
diff --git a/test/Import/struct-in-namespace/test.cpp b/test/Import/struct-in-namespace/test.cpp
new file mode 100644
index 000000000000..fd14d82d178c
--- /dev/null
+++ b/test/Import/struct-in-namespace/test.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -import %S/Inputs/N1.cpp -import %S/Inputs/N2.cpp -import %S/Inputs/N3.cpp -expression %s
+void expr() {
+ N::S s;
+ N::T t;
+ N::U u;
+ int d = s.a + t.b + u.c;
+}
diff --git a/test/Import/template-specialization/Inputs/T.cpp b/test/Import/template-specialization/Inputs/T.cpp
new file mode 100644
index 000000000000..b31e2439efeb
--- /dev/null
+++ b/test/Import/template-specialization/Inputs/T.cpp
@@ -0,0 +1,14 @@
+template <typename T> struct A {
+};
+
+template <> struct A<int> {
+ struct B {
+ int f;
+ };
+};
+
+template <> struct A<bool> {
+ struct B {
+ int g;
+ };
+};
diff --git a/test/Import/template-specialization/test.cpp b/test/Import/template-specialization/test.cpp
new file mode 100644
index 000000000000..43996c53a77e
--- /dev/null
+++ b/test/Import/template-specialization/test.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s
+// XFAIL: *
+void expr() {
+ A<int>::B b1;
+ A<bool>::B b2;
+ b1.f + b2.g;
+}
diff --git a/test/Index/Core/Inputs/sys/system-head.h b/test/Index/Core/Inputs/sys/system-head.h
new file mode 100644
index 000000000000..df0e39ed8613
--- /dev/null
+++ b/test/Index/Core/Inputs/sys/system-head.h
@@ -0,0 +1,36 @@
+// CHECK: [[@LINE+1]]:12 | class/ObjC | Base | [[Base_USR:.*]] | {{.*}} | Decl | rel: 0
+@interface Base
+@end
+
+// CHECK: [[@LINE+1]]:11 | protocol/ObjC | Prot1 | [[Prot1_USR:.*]] | {{.*}} | Decl | rel: 0
+@protocol Prot1
+@end
+
+// CHECK: [[@LINE+3]]:11 | protocol/ObjC | Prot2 | [[Prot2_USR:.*]] | {{.*}} | Decl | rel: 0
+// CHECK: [[@LINE+2]]:17 | protocol/ObjC | Prot1 | [[Prot1_USR]] | {{.*}} | Ref,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | Prot2 | [[Prot2_USR]]
+@protocol Prot2<Prot1>
+@end
+
+// CHECK: [[@LINE+7]]:12 | class/ObjC | Sub | [[Sub_USR:.*]] | {{.*}} | Decl | rel: 0
+// CHECK: [[@LINE+6]]:18 | class/ObjC | Base | [[Base_USR]] | {{.*}} | Ref,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | Sub | [[Sub_USR]]
+// CHECK: [[@LINE+4]]:23 | protocol/ObjC | Prot2 | [[Prot2_USR]] | {{.*}} | Ref,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | Sub | [[Sub_USR]]
+// CHECK: [[@LINE+2]]:30 | protocol/ObjC | Prot1 | [[Prot1_USR]] | {{.*}} | Ref,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | Sub | [[Sub_USR]]
+@interface Sub : Base<Prot2, Prot1>
+// CHECK-NOT: [[@LINE+1]]:3 | class/ObjC | Sub |
+-(Sub*)getit;
+@end
+
+// CHECK: [[@LINE+1]]:7 | class/C++ | Cls | [[Cls_USR:.*]] | {{.*}} | Def | rel: 0
+class Cls {};
+
+// CHECK: [[@LINE+3]]:7 | class/C++ | SubCls1 | [[SubCls1_USR:.*]] | {{.*}} | Def | rel: 0
+// CHECK: [[@LINE+2]]:24 | class/C++ | Cls | [[Cls_USR]] | {{.*}} | Ref,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | SubCls1 | [[SubCls1_USR]]
+class SubCls1 : public Cls {
+ // CHECK-NOT: [[@LINE+1]]:3 | class/C++ | SubCls1 |
+ SubCls1 *f;
+};
diff --git a/test/Index/Core/index-pch.c b/test/Index/Core/index-pch.c
new file mode 100644
index 000000000000..773cfc59077e
--- /dev/null
+++ b/test/Index/Core/index-pch.c
@@ -0,0 +1,13 @@
+// RUN: c-index-test core -print-source-symbols -- %s | FileCheck %s
+// RUN: %clang_cc1 -emit-pch %s -o %t.pch
+// RUN: c-index-test core -print-source-symbols -module-file %t.pch | FileCheck %s
+
+// CHECK: [[@LINE+1]]:6 | function/C | test1 | [[TEST1_USR:.*]] | [[TEST1_CG:.*]] | Decl | rel: 0
+void test1();
+
+// CHECK: [[@LINE+1]]:20 | function/C | test2 | [[TEST2_USR:.*]] | {{.*}} | Def | rel: 0
+static inline void test2() {
+ // CHECK: [[@LINE+2]]:3 | function/C | test1 | [[TEST1_USR]] | [[TEST1_CG]] | Ref,Call,RelCall,RelCont | rel: 1
+ // CHECK-NEXT: RelCall,RelCont | test2 | [[TEST2_USR]]
+ test1();
+}
diff --git a/test/Index/Core/index-source.cpp b/test/Index/Core/index-source.cpp
index 68eafecf6795..356d4a08de3a 100644
--- a/test/Index/Core/index-source.cpp
+++ b/test/Index/Core/index-source.cpp
@@ -1,16 +1,46 @@
// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s
-// CHECK: [[@LINE+1]]:7 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Def | rel: 0
+// CHECK: [[@LINE+1]]:7 | class/C++ | Cls | [[Cls_USR:.*]] | <no-cgname> | Def | rel: 0
class Cls {
- // CHECK: [[@LINE+2]]:3 | constructor/C++ | Cls | c:@S@Cls@F@Cls#I# | __ZN3ClsC1Ei | Decl,RelChild | rel: 1
+ // CHECK: [[@LINE+3]]:3 | constructor/C++ | Cls | c:@S@Cls@F@Cls#I# | __ZN3ClsC1Ei | Decl,RelChild | rel: 1
// CHECK-NEXT: RelChild | Cls | c:@S@Cls
+ // CHECK: [[@LINE+1]]:3 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
Cls(int x);
- // CHECK: [[@LINE+1]]:3 | constructor/cxx-copy-ctor/C++ | Cls | c:@S@Cls@F@Cls#&1$@S@Cls# | __ZN3ClsC1ERKS_ | Decl,RelChild | rel: 1
+ // CHECK: [[@LINE+2]]:3 | constructor/cxx-copy-ctor/C++ | Cls | c:@S@Cls@F@Cls#&1$@S@Cls# | __ZN3ClsC1ERKS_ | Decl,RelChild | rel: 1
+ // CHECK: [[@LINE+1]]:3 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
Cls(const Cls &);
- // CHECK: [[@LINE+1]]:3 | constructor/cxx-move-ctor/C++ | Cls | c:@S@Cls@F@Cls#&&$@S@Cls# | __ZN3ClsC1EOS_ | Decl,RelChild | rel: 1
+ // CHECK: [[@LINE+2]]:3 | constructor/cxx-move-ctor/C++ | Cls | c:@S@Cls@F@Cls#&&$@S@Cls# | __ZN3ClsC1EOS_ | Decl,RelChild | rel: 1
+ // CHECK: [[@LINE+1]]:3 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
Cls(Cls &&);
+
+ // CHECK: [[@LINE+2]]:3 | destructor/C++ | ~Cls | c:@S@Cls@F@~Cls# | __ZN3ClsD1Ev | Decl,RelChild | rel: 1
+ // CHECK: [[@LINE+1]]:4 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+ ~Cls();
};
+// CHECK: [[@LINE+3]]:7 | class/C++ | SubCls1 | [[SubCls1_USR:.*]] | <no-cgname> | Def | rel: 0
+// CHECK: [[@LINE+2]]:24 | class/C++ | Cls | [[Cls_USR]] | <no-cgname> | Ref,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | SubCls1 | [[SubCls1_USR]]
+class SubCls1 : public Cls {};
+// CHECK: [[@LINE+1]]:13 | type-alias/C | ClsAlias | [[ClsAlias_USR:.*]] | <no-cgname> | Def | rel: 0
+typedef Cls ClsAlias;
+// CHECK: [[@LINE+5]]:7 | class/C++ | SubCls2 | [[SubCls2_USR:.*]] | <no-cgname> | Def | rel: 0
+// CHECK: [[@LINE+4]]:24 | type-alias/C | ClsAlias | [[ClsAlias_USR]] | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | SubCls2 | [[SubCls2_USR]]
+// CHECK: [[@LINE+2]]:24 | class/C++ | Cls | [[Cls_USR]] | <no-cgname> | Ref,Impl,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | SubCls2 | [[SubCls2_USR]]
+class SubCls2 : public ClsAlias {};
+
+Cls::Cls(int x) {}
+// CHECK: [[@LINE-1]]:6 | constructor/C++ | Cls | c:@S@Cls@F@Cls#I# | __ZN3ClsC1Ei | Def,RelChild | rel: 1
+// CHECK: [[@LINE-2]]:1 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-3]]:6 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+
+Cls::~/*a comment*/Cls() {}
+// CHECK: [[@LINE-1]]:6 | destructor/C++ | ~Cls | c:@S@Cls@F@~Cls# | __ZN3ClsD1Ev | Def,RelChild | rel: 1
+// CHECK: [[@LINE-2]]:1 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-3]]:20 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+
template <typename TemplArg>
class TemplCls {
// CHECK: [[@LINE-1]]:7 | class(Gen)/C++ | TemplCls | c:@ST>1#T@TemplCls | <no-cgname> | Def | rel: 0
@@ -23,6 +53,16 @@ public:
TemplCls<int> gtv(0);
// CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | TemplCls | c:@ST>1#T@TemplCls | <no-cgname> | Ref,RelCont | rel: 1
+template<class T>
+class Wrapper {};
+template<class T, class P>
+class Wrapper<T(P)> {};
+
+// CHECK: [[@LINE+1]]:6 | function/C | test1 | [[TEST1_USR:.*]] | [[TEST1_CG:.*]] | Decl | rel: 0
+void test1(Wrapper<void(int)> f);
+// CHECK: [[@LINE+1]]:6 | function/C | test1 | [[TEST1_USR]] | [[TEST1_CG]] | Def | rel: 0
+void test1(Wrapper<void(int)> f) {}
+
template <typename T>
class BT {
struct KLR {
diff --git a/test/Index/Core/index-source.m b/test/Index/Core/index-source.m
index 880028df6310..f48891417f5f 100644
--- a/test/Index/Core/index-source.m
+++ b/test/Index/Core/index-source.m
@@ -1,4 +1,5 @@
// RUN: c-index-test core -print-source-symbols -- %s -target x86_64-apple-macosx10.7 | FileCheck %s
+// RUN: c-index-test core -print-source-symbols -include-locals -- %s -target x86_64-apple-macosx10.7 | FileCheck -check-prefix=LOCAL %s
@interface Base
// CHECK: [[@LINE-1]]:12 | class/ObjC | Base | c:objc(cs)Base | _OBJC_CLASS_$_Base | Decl | rel: 0
@@ -13,10 +14,33 @@
@end
void foo();
-// CHECK: [[@LINE+3]]:6 | function/C | goo | c:@F@goo | _goo | Def | rel: 0
-// CHECK: [[@LINE+2]]:10 | class/ObjC | Base | c:objc(cs)Base | _OBJC_CLASS_$_Base | Ref,RelCont | rel: 1
+// CHECK: [[@LINE+6]]:6 | function/C | goo | c:@F@goo | _goo | Def | rel: 0
+// CHECK: [[@LINE+5]]:10 | class/ObjC | Base | c:objc(cs)Base | _OBJC_CLASS_$_Base | Ref,RelCont | rel: 1
// CHECK-NEXT: RelCont | goo | c:@F@goo
+// CHECK-NOT: [[@LINE+3]]:16 | param
+// LOCAL: [[@LINE+2]]:16 | param(local)/C | b | [[b_USR:c:.*]] | _b | Def,RelChild | rel: 1
+// LOCAL-NEXT: RelChild | goo | c:@F@goo
void goo(Base *b) {
+ // CHECK-NOT: [[@LINE+6]]:7 | variable
+ // LOCAL: [[@LINE+5]]:7 | variable(local)/C | x | [[x_USR:c:.*]] | _x | Def,RelCont | rel: 1
+ // LOCAL-NEXT: RelCont | goo | c:@F@goo
+ // CHECK-NOT: [[@LINE+3]]:11 | param
+ // LOCAL: [[@LINE+2]]:11 | param(local)/C | b | [[b_USR]] | _b | Ref,Read,RelCont | rel: 1
+ // LOCAL-NEXT: RelCont | x | [[x_USR]]
+ int x = b;
+ // CHECK-NOT: [[@LINE+5]]:7 | variable
+ // LOCAL: [[@LINE+4]]:7 | variable(local)/C | y | [[y_USR:c:.*]] | _y | Def,RelCont | rel: 1
+ // CHECK-NOT: [[@LINE+3]]:11 | variable
+ // LOCAL: [[@LINE+2]]:11 | variable(local)/C | x | [[x_USR]] | _x | Ref,Read,RelCont | rel: 1
+ // LOCAL-NEXT: RelCont | y | [[y_USR]]
+ int y = x;
+
+ // CHECK-NOT: [[@LINE+1]]:10 | struct
+ // LOCAL: [[@LINE+1]]:10 | struct(local)/C | Foo | c:{{.*}} | <no-cgname> | Def,RelCont | rel: 1
+ struct Foo {
+ int i;
+ };
+
// CHECK: [[@LINE+2]]:3 | function/C | foo | c:@F@foo | _foo | Ref,Call,RelCall,RelCont | rel: 1
// CHECK-NEXT: RelCall,RelCont | goo | c:@F@goo
foo();
@@ -97,32 +121,79 @@ extern int setjmp(jmp_buf);
@end
@interface I2
+// CHECK: [[@LINE-1]]:12 | class/ObjC | I2 | [[I2_USR:.*]] | {{.*}} | Decl | rel: 0
+
@property (readwrite) id prop;
+// CHECK: [[@LINE-1]]:26 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR:.*]] | -[I2 prop] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2
+// CHECK: [[@LINE-2]]:26 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR:.*]] | -[I2 setProp:] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2
+// CHECK: [[@LINE-3]]:26 | instance-property/ObjC | prop | [[I2_prop_USR:.*]] | <no-cgname> | Decl,RelChild | rel: 1
-// CHECK: [[@LINE+4]]:63 | instance-property(IB,IBColl)/ObjC | buttons | c:objc(cs)I2(py)buttons | <no-cgname> | Decl,RelChild | rel: 1
-// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2
+@property (readwrite, getter=customGet, setter=customSet:) id unrelated;
+// CHECK: [[@LINE-1]]:30 | instance-method/acc-get/ObjC | customGet | {{.*}} | -[I2 customGet] | Decl,Dyn,RelChild,RelAcc | rel: 2
+// CHECK: [[@LINE-2]]:48 | instance-method/acc-set/ObjC | customSet: | {{.*}} | -[I2 customSet:] | Decl,Dyn,RelChild,RelAcc | rel: 2
+// CHECK: [[@LINE-3]]:63 | instance-property/ObjC | unrelated | {{.*}} | <no-cgname> | Decl,RelChild | rel: 1
+
+-(id)declaredGet;
+@property (readwrite, getter=declaredGet) id otherProp;
+// CHECK: [[@LINE-1]]:30 | instance-method/acc-get/ObjC | declaredGet | {{.*}} | -[I2 declaredGet] | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-3]]:6 | instance-method/acc-get/ObjC | declaredGet | {{.*}} | -[I2 declaredGet] | Decl,Dyn,RelChild,RelAcc | rel: 2
+// CHECK: [[@LINE-3]]:46 | instance-method/acc-set/ObjC | setOtherProp: | {{.*}} | -[I2 setOtherProp:] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2
+
+// CHECK: [[@LINE+4]]:63 | instance-property(IB,IBColl)/ObjC | buttons | [[buttons_USR:.*]] | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I2 | [[I2_USR]]
// CHECK: [[@LINE+2]]:50 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont,RelIBType | rel: 1
-// CHECK-NEXT: RelCont,RelIBType | buttons | c:objc(cs)I2(py)buttons
+// CHECK-NEXT: RelCont,RelIBType | buttons | [[buttons_USR]]
@property (nonatomic, strong) IBOutletCollection(I1) NSArray *buttons;
@end
-// CHECK: [[@LINE+2]]:17 | field/ObjC | _prop | c:objc(cs)I2@_prop | <no-cgname> | Def,Impl,RelChild | rel: 1
-// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2
@implementation I2
-// CHECK: [[@LINE+6]]:13 | instance-property/ObjC | prop | c:objc(cs)I2(py)prop | <no-cgname> | Ref,RelCont | rel: 1
-// CHECK-NEXT: RelCont | I2 | c:objc(cs)I2
-// CHECK: [[@LINE+4]]:13 | instance-method/acc-get/ObjC | prop | c:objc(cs)I2(im)prop | -[I2 prop] | Def,RelChild | rel: 1
-// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2
-// CHECK: [[@LINE+2]]:13 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I2(im)setProp: | -[I2 setProp:] | Def,RelChild | rel: 1
-// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2
+// CHECK: [[@LINE+9]]:13 | instance-property/ObjC | prop | [[I2_prop_USR:.*]] | <no-cgname> | Def,RelChild,RelAcc | rel: 2
+// CHECK-NEXT: RelChild | I2 | [[I2_USR]]
+// CHECK-NEXT: RelAcc | _prop | c:objc(cs)I2@_prop
+// CHECK: [[@LINE+6]]:13 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I2 | [[I2_USR]]
+// CHECK: [[@LINE+4]]:13 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR]] | -[I2 setProp:] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I2 | [[I2_USR]]
+// CHECK: [[@LINE+2]]:20 | field/ObjC | _prop | c:objc(cs)I2@_prop | <no-cgname> | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I2 | [[I2_USR]]
@synthesize prop = _prop;
-// CHECK: [[@LINE+5]]:12 | instance-method(IB)/ObjC | doAction:foo: | c:objc(cs)I2(im)doAction:foo: | -[I2 doAction:foo:] | Def,Dyn,RelChild | rel: 1
-// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2
-// CHECK: [[@LINE+3]]:22 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont,RelIBType | rel: 1
-// CHECK-NEXT: RelCont,RelIBType | doAction:foo: | c:objc(cs)I2(im)doAction:foo:
-// CHECK: [[@LINE+1]]:39 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont | rel: 1
--(IBAction)doAction:(I1 *)sender foo:(I1 *)bar {}
+// CHECK: [[@LINE+11]]:12 | instance-method(IB)/ObjC | doAction:foo: | [[doAction_USR:.*]] | -[I2 doAction:foo:] | Def,Dyn,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I2 | [[I2_USR]]
+// CHECK: [[@LINE+9]]:22 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont,RelIBType | rel: 1
+// CHECK-NEXT: RelCont,RelIBType | doAction:foo: | [[doAction_USR]]
+// CHECK-NOT: [[@LINE+7]]:27 | param
+// LOCAL: [[@LINE+6]]:27 | param(local)/C | sender | c:{{.*}} | _sender | Def,RelChild | rel: 1
+// LOCAL-NEXT: RelChild | doAction:foo: | [[doAction_USR:.*]]
+// CHECK: [[@LINE+4]]:39 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont | rel: 1
+// CHECK-NOT: [[@LINE+3]]:44 | param
+// LOCAL: [[@LINE+2]]:44 | param(local)/C | bar | c:{{.*}} | _bar | Def,RelChild | rel: 1
+// LOCAL-NEXT: RelChild | doAction:foo: | [[doAction_USR]]
+-(IBAction)doAction:(I1 *)sender foo:(I1 *)bar {
+ [self prop];
+ // CHECK: [[@LINE-1]]:9 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2
+ // CHECK-NEXT: RelCall,RelCont | doAction:foo: | [[doAction_USR]]
+ // CHECK-NEXT: RelRec | I2 | [[I2_USR]]
+
+ [self setProp: bar];
+ // CHECK: [[@LINE-1]]:9 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR]] | -[I2 setProp:] | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2
+ // CHECK-NEXT: RelCall,RelCont | doAction:foo: | [[doAction_USR]]
+ // CHECK-NEXT: RelRec | I2 | [[I2_USR]]
+
+ self.prop;
+ // CHECK: [[@LINE-1]]:8 | instance-property/ObjC | prop | [[I2_prop_USR]] | <no-cgname> | Ref,RelCont | rel: 1
+ // CHECK-NEXT: RelCont | doAction:foo: | [[doAction_USR]]
+ // CHECK: [[@LINE-3]]:8 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Ref,Call,Dyn,Impl,RelRec,RelCall,RelCont | rel: 2
+ // CHECK-NEXT: RelCall,RelCont | doAction:foo: | [[doAction_USR]]
+ // CHECK-NEXT: RelRec | I2 | [[I2_USR]]
+
+ self.prop = self.prop;
+ // CHECK: [[@LINE-1]]:8 | instance-property/ObjC | prop | [[I2_prop_USR]] | <no-cgname> | Ref,Writ,RelCont | rel: 1
+ // CHECK-NEXT: RelCont | doAction:foo: | [[doAction_USR]]
+ // CHECK:[[@LINE-3]]:8 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR]] | -[I2 setProp:] | Ref,Call,Dyn,Impl,RelRec,RelCall,RelCont | rel: 2
+ // CHECK-NEXT: RelCall,RelCont | doAction:foo: | [[doAction_USR]]
+ // CHECK-NEXT: RelRec | I2 | [[I2_USR]]
+}
@end
@interface I3
@@ -131,18 +202,20 @@ extern int setjmp(jmp_buf);
// CHECK-NEXT: RelChild | I3 | c:objc(cs)I3
// CHECK-NEXT: RelAcc | prop | c:objc(cs)I3(py)prop
-(id)prop;
-// CHECK: [[@LINE+3]]:8 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Decl,Dyn,RelChild,RelAcc | rel: 2
+// CHECK: [[@LINE+4]]:8 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Decl,Dyn,RelChild,RelAcc | rel: 2
// CHECK-NEXT: RelChild | I3 | c:objc(cs)I3
// CHECK-NEXT: RelAcc | prop | c:objc(cs)I3(py)prop
+// LOCAL-NOT: [[@LINE+1]]:20 | param
-(void)setProp:(id)p;
@end
// CHECK: [[@LINE+1]]:17 | class/ObjC | I3 | c:objc(cs)I3 | <no-cgname> | Def | rel: 0
@implementation I3
-// CHECK: [[@LINE+4]]:13 | instance-property/ObjC | prop | c:objc(cs)I3(py)prop | <no-cgname> | Ref,RelCont | rel: 1
-// CHECK-NEXT: RelCont | I3 | c:objc(cs)I3
-// CHECK: [[@LINE+2]]:13 | instance-method/acc-get/ObjC | prop | c:objc(cs)I3(im)prop | -[I3 prop] | Def,RelChild | rel: 1
-// CHECK: [[@LINE+1]]:13 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Def,RelChild | rel: 1
+// CHECK: [[@LINE+5]]:13 | instance-property/ObjC | prop | c:objc(cs)I3(py)prop | <no-cgname> | Def,RelChild,RelAcc | rel: 2
+// CHECK-NEXT: RelChild | I3 | c:objc(cs)I3
+// CHECK-NEXT: RelAcc | _prop | c:objc(cs)I3@_prop
+// CHECK: [[@LINE+2]]:13 | instance-method/acc-get/ObjC | prop | c:objc(cs)I3(im)prop | -[I3 prop] | Def,Impl,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:13 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Def,Impl,RelChild | rel: 1
@synthesize prop = _prop;
@end
@@ -155,7 +228,7 @@ extern int setjmp(jmp_buf);
@end
// CHECK: [[@LINE+2]]:17 | class/ObjC | I3 | c:objc(cs)I3 | _OBJC_CLASS_$_I3 | Ref,RelCont | rel: 1
-// CHECK: [[@LINE+1]]:20 | extension/ObjC | I3 | c:objc(cy)I3@bar | <no-cgname> | Def | rel: 0
+// CHECK: [[@LINE+1]]:20 | extension/ObjC | bar | c:objc(cy)I3@bar | <no-cgname> | Def | rel: 0
@implementation I3(bar)
@end
@@ -169,16 +242,145 @@ extern int setjmp(jmp_buf);
@protocol MyEnumerating
@end
-// CHECK: [[@LINE+4]]:41 | type-alias/C | MyEnumerator | c:index-source.m@T@MyEnumerator | <no-cgname> | Def | rel: 0
+// CHECK: [[@LINE+4]]:41 | type-alias/C | MyEnumerator | [[MyEnumerator_USR:.*]] | <no-cgname> | Def | rel: 0
// CHECK: [[@LINE+3]]:26 | protocol/ObjC | MyEnumerating | c:objc(pl)MyEnumerating | <no-cgname> | Ref,RelCont | rel: 1
// CHECK: [[@LINE+2]]:9 | class/ObjC | MyGenCls | c:objc(cs)MyGenCls | _OBJC_CLASS_$_MyGenCls | Ref,RelCont | rel: 1
// CHECK: [[@LINE+1]]:18 | class/ObjC | Base | c:objc(cs)Base | _OBJC_CLASS_$_Base | Ref,RelCont | rel: 1
typedef MyGenCls<Base *><MyEnumerating> MyEnumerator;
-// CHECK: [[@LINE+5]]:12 | class/ObjC | PermanentEnumerator | c:objc(cs)PermanentEnumerator | _OBJC_CLASS_$_PermanentEnumerator | Decl | rel: 0
-// CHECK: [[@LINE+4]]:34 | class/ObjC | MyGenCls | c:objc(cs)MyGenCls | _OBJC_CLASS_$_MyGenCls | Ref,RelBase,RelCont | rel: 1
-// CHECK-NEXT: RelBase,RelCont | PermanentEnumerator | c:objc(cs)PermanentEnumerator
-// CHECK: [[@LINE+2]]:34 | protocol/ObjC | MyEnumerating | c:objc(pl)MyEnumerating | <no-cgname> | Ref,RelBase,RelCont | rel: 1
-// CHECK-NEXT: RelBase,RelCont | PermanentEnumerator | c:objc(cs)PermanentEnumerator
+// CHECK: [[@LINE+7]]:12 | class/ObjC | PermanentEnumerator | [[PermanentEnumerator_USR:.*]] | _OBJC_CLASS_$_PermanentEnumerator | Decl | rel: 0
+// CHECK: [[@LINE+6]]:34 | type-alias/C | MyEnumerator | [[MyEnumerator_USR]] | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | PermanentEnumerator | [[PermanentEnumerator_USR]]
+// CHECK: [[@LINE+4]]:34 | class/ObjC | MyGenCls | c:objc(cs)MyGenCls | _OBJC_CLASS_$_MyGenCls | Ref,Impl,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | PermanentEnumerator | [[PermanentEnumerator_USR]]
+// CHECK: [[@LINE+2]]:34 | protocol/ObjC | MyEnumerating | c:objc(pl)MyEnumerating | <no-cgname> | Ref,Impl,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | PermanentEnumerator | [[PermanentEnumerator_USR]]
@interface PermanentEnumerator : MyEnumerator
@end
+
+// CHECK: [[@LINE+2]]:48 | protocol/ObjC | Prot1 | c:objc(pl)Prot1 | <no-cgname> | Ref,RelBase,RelCont | rel: 1
+// CHECK: [[@LINE+1]]:35 | protocol/ObjC | MyEnumerating | c:objc(pl)MyEnumerating | <no-cgname> | Ref,Impl,RelBase,RelCont | rel: 1
+@interface PermanentEnumerator2 : MyEnumerator<Prot1>
+@end
+
+@interface I4
+@property id foo;
+@end
+
+@implementation I4 {
+ id _blahfoo; // explicit def
+ // CHECK: [[@LINE-1]]:6 | field/ObjC | _blahfoo | c:objc(cs)I4@_blahfoo | <no-cgname> | Def,RelChild | rel: 1
+}
+@synthesize foo = _blahfoo; // ref of field _blahfoo
+// CHECK: [[@LINE-1]]:13 | instance-property/ObjC | foo | c:objc(cs)I4(py)foo | <no-cgname> | Def,RelChild,RelAcc | rel: 2
+// CHECK-NEXT: RelChild | I4 | c:objc(cs)I4
+// CHECK-NEXT: RelAcc | _blahfoo | c:objc(cs)I4@_blahfoo
+// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I4(im)foo | -[I4 foo] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I4 | c:objc(cs)I4
+// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I4(im)setFoo: | -[I4 setFoo:] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I4 | c:objc(cs)I4
+// CHECK: [[@LINE-8]]:19 | field/ObjC | _blahfoo | c:objc(cs)I4@_blahfoo | <no-cgname> | Ref | rel: 0
+
+-(void)method {
+ _blahfoo = 0;
+ // CHECK: [[@LINE-1]]:3 | field/ObjC | _blahfoo | c:objc(cs)I4@_blahfoo | <no-cgname> | Ref,Writ,RelCont | rel: 1
+}
+@end
+
+@interface I5
+@property id foo;
+@end
+
+@implementation I5
+@synthesize foo = _blahfoo; // explicit def of field _blahfoo
+// CHECK: [[@LINE-1]]:13 | instance-property/ObjC | foo | c:objc(cs)I5(py)foo | <no-cgname> | Def,RelChild,RelAcc | rel: 2
+// CHECK-NEXT: RelChild | I5 | c:objc(cs)I5
+// CHECK-NEXT: RelAcc | _blahfoo | c:objc(cs)I5@_blahfoo
+// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I5(im)foo | -[I5 foo] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I5 | c:objc(cs)I5
+// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I5(im)setFoo: | -[I5 setFoo:] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I5 | c:objc(cs)I5
+// CHECK: [[@LINE-8]]:19 | field/ObjC | _blahfoo | c:objc(cs)I5@_blahfoo | <no-cgname> | Def,RelChild | rel: 1
+
+-(void)method {
+ _blahfoo = 0;
+ // CHECK: [[@LINE-1]]:3 | field/ObjC | _blahfoo | c:objc(cs)I5@_blahfoo | <no-cgname> | Ref,Writ,RelCont | rel: 1
+}
+@end
+
+@interface I6
+@property id foo;
+@end
+
+@implementation I6
+@synthesize foo; // implicit def of field foo
+// CHECK: [[@LINE-1]]:13 | instance-property/ObjC | foo | c:objc(cs)I6(py)foo | <no-cgname> | Def,RelChild,RelAcc | rel: 2
+// CHECK-NEXT: RelChild | I6 | c:objc(cs)I6
+// CHECK-NEXT: RelAcc | foo | c:objc(cs)I6@foo
+// CHECK: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I6(im)foo | -[I6 foo] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I6 | c:objc(cs)I6
+// CHECK: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I6(im)setFoo: | -[I6 setFoo:] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I6 | c:objc(cs)I6
+// CHECK: [[@LINE-8]]:13 | field/ObjC | foo | c:objc(cs)I6@foo | <no-cgname> | Def,Impl,RelChild | rel: 1
+
+-(void)method {
+ foo = 0;
+ // CHECK: [[@LINE-1]]:3 | field/ObjC | foo | c:objc(cs)I6@foo | <no-cgname> | Ref,Writ,RelCont | rel: 1
+}
+@end
+
+@interface I7
+@property id foo;
+@end
+
+@implementation I7 // implicit def of field _foo
+// CHECK: [[@LINE-1]]:17 | instance-property/ObjC | foo | c:objc(cs)I7(py)foo | <no-cgname> | Def,Impl,RelChild,RelAcc | rel: 2
+// CHECK-NEXT: RelChild | I7 | c:objc(cs)I7
+// CHECK-NEXT: RelAcc | _foo | c:objc(cs)I7@_foo
+// CHECK: [[@LINE-4]]:17 | instance-method/acc-get/ObjC | foo | c:objc(cs)I7(im)foo | -[I7 foo] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I7 | c:objc(cs)I7
+// CHECK: [[@LINE-6]]:17 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I7(im)setFoo: | -[I7 setFoo:] | Def,Impl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | I7 | c:objc(cs)I7
+// CHECK: [[@LINE-8]]:17 | field/ObjC | _foo | c:objc(cs)I7@_foo | <no-cgname> | Def,Impl,RelChild | rel: 1
+
+-(void)method {
+ _foo = 0;
+// CHECK: [[@LINE-1]]:3 | field/ObjC | _foo | c:objc(cs)I7@_foo | <no-cgname> | Ref,Writ,RelCont | rel: 1
+}
+@end
+
+#define NS_ENUM(_name, _type) enum _name:_type _name; enum _name : _type
+
+typedef NS_ENUM(AnotherEnum, int) {
+// CHECK-NOT: [[@LINE-1]]:17 | type-alias/C | AnotherEnum |
+// CHECK: [[@LINE-2]]:17 | enum/C | AnotherEnum | [[AnotherEnum_USR:.*]] | {{.*}} | Ref,RelCont | rel: 1
+ AnotherEnumFirst = 0,
+ AnotherEnumSecond = 1,
+ AnotherEnumThird = 2,
+};
+
+AnotherEnum anotherT;
+// CHECK: [[@LINE-1]]:1 | enum/C | AnotherEnum | [[AnotherEnum_USR]] | {{.*}} | Ref,RelCont | rel: 1
+enum AnotherEnum anotherE;
+// CHECK: [[@LINE-1]]:6 | enum/C | AnotherEnum | [[AnotherEnum_USR]] | {{.*}} | Ref,RelCont | rel: 1
+
+#define TRANSPARENT(_name) struct _name _name; struct _name
+#define OPAQUE(_name) struct _name *_name; struct _name
+
+typedef TRANSPARENT(AStruct) {
+ int x;
+};
+
+AStruct aStructT;
+// CHECK: [[@LINE-1]]:1 | struct/C | AStruct | {{.*}} | {{.*}} | Ref,RelCont | rel: 1
+struct AStruct aStructS;
+// CHECK: [[@LINE-1]]:8 | struct/C | AStruct | {{.*}} | {{.*}} | Ref,RelCont | rel: 1
+
+typedef OPAQUE(Separate) {
+ int x;
+};
+
+Separate separateT;
+// CHECK: [[@LINE-1]]:1 | type-alias/C | Separate | {{.*}} | {{.*}} | Ref,RelCont | rel: 1
+struct Separate separateE;
+// CHECK: [[@LINE-1]]:8 | struct/C | Separate | {{.*}} | {{.*}} | Ref,RelCont | rel: 1
diff --git a/test/Index/Core/index-subkinds.m b/test/Index/Core/index-subkinds.m
index 15d60b151896..5eea046721b6 100644
--- a/test/Index/Core/index-subkinds.m
+++ b/test/Index/Core/index-subkinds.m
@@ -28,11 +28,11 @@
// CHECK: [[@LINE+3]]:12 | class(test)/ObjC | MyTestCase | c:objc(cs)MyTestCase | _OBJC_CLASS_$_MyTestCase | Ref,RelExt,RelCont | rel: 1
// CHECK-NEXT: RelExt,RelCont | cat | c:objc(cy)MyTestCase@cat
-// CHECK: [[@LINE+1]]:23 | extension/ObjC | cat | c:objc(cy)MyTestCase@cat | <no-cgname> | Decl | rel: 0
+// CHECK: [[@LINE+1]]:23 | extension(test)/ObjC | cat | c:objc(cy)MyTestCase@cat | <no-cgname> | Decl | rel: 0
@interface MyTestCase(cat)
@end
// CHECK: [[@LINE+2]]:17 | class(test)/ObjC | MyTestCase | c:objc(cs)MyTestCase | _OBJC_CLASS_$_MyTestCase | Ref,RelCont | rel: 1
-// CHECK: [[@LINE+1]]:28 | extension/ObjC | MyTestCase | c:objc(cy)MyTestCase@cat | <no-cgname> | Def | rel: 0
+// CHECK: [[@LINE+1]]:28 | extension(test)/ObjC | cat | c:objc(cy)MyTestCase@cat | <no-cgname> | Def | rel: 0
@implementation MyTestCase(cat)
// CHECK: [[@LINE+1]]:9 | instance-method(test)/ObjC | testInCat | c:objc(cs)MyTestCase(im)testInCat | -[MyTestCase(cat) testInCat] | Def,Dyn,RelChild | rel: 1
- (void)testInCat {}
@@ -42,7 +42,7 @@
@class NSButton;
@interface IBCls
-// CHECK: [[@LINE+2]]:34 | instance-method/acc-get/ObjC | prop | c:objc(cs)IBCls(im)prop | -[IBCls prop] | Decl,Dyn,RelChild,RelAcc | rel: 2
+// CHECK: [[@LINE+2]]:34 | instance-method/acc-get/ObjC | prop | c:objc(cs)IBCls(im)prop | -[IBCls prop] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2
// CHECK: [[@LINE+1]]:34 | instance-property(IB)/ObjC | prop | c:objc(cs)IBCls(py)prop | <no-cgname> | Decl,RelChild | rel: 1
@property (readonly) IBOutlet id prop;
// CHECK: [[@LINE+1]]:54 | instance-property(IB,IBColl)/ObjC | propColl | c:objc(cs)IBCls(py)propColl | <no-cgname> | Decl,RelChild | rel: 1
diff --git a/test/Index/Core/index-system.mm b/test/Index/Core/index-system.mm
new file mode 100644
index 000000000000..2ad31fae714f
--- /dev/null
+++ b/test/Index/Core/index-system.mm
@@ -0,0 +1,3 @@
+// RUN: c-index-test core -print-source-symbols -- %s -isystem %S/Inputs/sys | FileCheck %S/Inputs/sys/system-head.h
+
+#include "system-head.h"
diff --git a/test/Index/Core/index-with-module.m b/test/Index/Core/index-with-module.m
index e50b247e8d57..c83de63701e1 100644
--- a/test/Index/Core/index-with-module.m
+++ b/test/Index/Core/index-with-module.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t.mcp
-// RUN: c-index-test core -print-source-symbols -- %s -I %S/Inputs/module -fmodules -fmodules-cache-path=%t.mcp | FileCheck %s
+// RUN: c-index-test core -print-source-symbols -dump-imported-module-files -- %s -I %S/Inputs/module -fmodules -fmodules-cache-path=%t.mcp | FileCheck %s
// CHECK: [[@LINE+1]]:9 | module/C | ModA | Decl |
@import ModA;
@@ -10,3 +10,9 @@ void foo() {
// CHECK: [[@LINE+1]]:3 | function/C | ModA_func | c:@F@ModA_func | {{.*}} | Ref,Call,RelCall,RelCont | rel: 1
ModA_func();
}
+
+// CHECK: ==== Module ModA ====
+// CHECK: 2:6 | function/C | ModA_func | c:@F@ModA_func | {{.*}} | Decl | rel: 0
+// CHECK: ---- Module Inputs ----
+// CHECK: user | {{.*}}ModA.h
+// CHECK: user | {{.*}}module.modulemap
diff --git a/test/Index/annotate-nested-name-specifier.cpp b/test/Index/annotate-nested-name-specifier.cpp
index eddd215a6779..a7338db6b05b 100644
--- a/test/Index/annotate-nested-name-specifier.cpp
+++ b/test/Index/annotate-nested-name-specifier.cpp
@@ -211,7 +211,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [40:30 - 40:32] UsingDeclaration=iterator:40:46
// CHECK: Identifier: "vector" [40:32 - 40:38] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [40:38 - 40:39] UsingDeclaration=iterator:40:46
-// CHECK: Identifier: "type" [40:39 - 40:43] TypeRef=type:39:13
+// CHECK: Identifier: "type" [40:39 - 40:43] TypeRef=X2::type:39:13
// CHECK: Punctuation: ">" [40:43 - 40:44] UsingDeclaration=iterator:40:46
// CHECK: Punctuation: "::" [40:44 - 40:46] UsingDeclaration=iterator:40:46
// CHECK: Identifier: "iterator" [40:46 - 40:54] UsingDeclaration=iterator:40:46
@@ -223,7 +223,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [41:21 - 41:23] UsingDeclaration=push_back:41:37
// CHECK: Identifier: "vector" [41:23 - 41:29] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [41:29 - 41:30] UsingDeclaration=push_back:41:37
-// CHECK: Identifier: "type" [41:30 - 41:34] TypeRef=type:39:13
+// CHECK: Identifier: "type" [41:30 - 41:34] TypeRef=X2::type:39:13
// CHECK: Punctuation: ">" [41:34 - 41:35] UsingDeclaration=push_back:41:37
// CHECK: Punctuation: "::" [41:35 - 41:37] UsingDeclaration=push_back:41:37
// CHECK: Identifier: "push_back" [41:37 - 41:46] UsingDeclaration=push_back:41:37
@@ -266,7 +266,7 @@ struct X9 : X8 {
// CHECK: Identifier: "vector" [57:51 - 57:57] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [57:57 - 57:58] MemberRefExpr=
// CHECK: Identifier: "T" [57:58 - 57:59] TypeRef=T:54:19
-// CHECK: Punctuation: ">" [57:59 - 57:60] CallExpr=
+// CHECK: Punctuation: ">" [57:59 - 57:60] MemberRefExpr=
// CHECK: Punctuation: "(" [57:60 - 57:61] CallExpr=
// CHECK: Punctuation: ")" [57:61 - 57:62] CallExpr=
@@ -283,7 +283,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [76:5 - 76:7] MemberRefExpr=[71:8, 72:8]
// CHECK: Identifier: "X4" [76:7 - 76:9] TemplateRef=X4:69:8
// CHECK: Punctuation: "<" [76:9 - 76:10] MemberRefExpr=[71:8, 72:8]
-// CHECK: Identifier: "type" [76:10 - 76:14] TypeRef=type:70:13
+// CHECK: Identifier: "type" [76:10 - 76:14] TypeRef=X4::type:70:13
// CHECK: Punctuation: ">" [76:14 - 76:15] MemberRefExpr=[71:8, 72:8]
// CHECK: Punctuation: "::" [76:15 - 76:17] MemberRefExpr=[71:8, 72:8]
// CHECK: Identifier: "g" [76:17 - 76:18] OverloadedDeclRef=g[71:8, 72:8]
@@ -296,7 +296,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [77:11 - 77:13] MemberRefExpr=
// CHECK: Identifier: "X4" [77:13 - 77:15] TemplateRef=X4:69:8
// CHECK: Punctuation: "<" [77:15 - 77:16] MemberRefExpr=
-// CHECK: Identifier: "type" [77:16 - 77:20] TypeRef=type:70:13
+// CHECK: Identifier: "type" [77:16 - 77:20] TypeRef=X4::type:70:13
// CHECK: Punctuation: ">" [77:20 - 77:21] MemberRefExpr=
// CHECK: Punctuation: "::" [77:21 - 77:23] MemberRefExpr=
// CHECK: Identifier: "g" [77:23 - 77:24] MemberRefExpr=
@@ -318,7 +318,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [91:5 - 91:7] MemberRefExpr=g:86:8
// CHECK: Identifier: "X4" [91:7 - 91:9] TemplateRef=X4:69:8
// CHECK: Punctuation: "<" [91:9 - 91:10] MemberRefExpr=g:86:8
-// CHECK: Identifier: "type" [91:10 - 91:14] TypeRef=type:84:19
+// CHECK: Identifier: "type" [91:10 - 91:14] TypeRef=X4<int>::type:84:19
// CHECK: Punctuation: ">" [91:14 - 91:15] MemberRefExpr=g:86:8
// CHECK: Punctuation: "::" [91:15 - 91:17] MemberRefExpr=g:86:8
// CHECK: Identifier: "g" [91:17 - 91:18] MemberRefExpr=g:86:8
@@ -331,7 +331,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [92:11 - 92:13] MemberRefExpr=g:86:8
// CHECK: Identifier: "X4" [92:13 - 92:15] TemplateRef=X4:69:8
// CHECK: Punctuation: "<" [92:15 - 92:16] MemberRefExpr=g:86:8
-// CHECK: Identifier: "type" [92:16 - 92:20] TypeRef=type:84:19
+// CHECK: Identifier: "type" [92:16 - 92:20] TypeRef=X4<int>::type:84:19
// CHECK: Punctuation: ">" [92:20 - 92:21] MemberRefExpr=g:86:8
// CHECK: Punctuation: "::" [92:21 - 92:23] MemberRefExpr=g:86:8
// CHECK: Identifier: "g" [92:23 - 92:24] MemberRefExpr=g:86:8
@@ -348,7 +348,7 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [100:38 - 100:40] TypedefDecl=iter_type:100:63 (Definition)
// CHECK: Identifier: "vector" [100:40 - 100:46] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [100:46 - 100:47] TypedefDecl=iter_type:100:63 (Definition)
-// CHECK: Identifier: "type" [100:47 - 100:51] TypeRef=type:99:13
+// CHECK: Identifier: "type" [100:47 - 100:51] TypeRef=X5::type:99:13
// CHECK: Punctuation: ">" [100:51 - 100:52] TypedefDecl=iter_type:100:63 (Definition)
// CHECK: Punctuation: "::" [100:52 - 100:54] TypedefDecl=iter_type:100:63 (Definition)
// CHECK: Identifier: "iterator" [100:54 - 100:62] TypedefDecl=iter_type:100:63 (Definition)
@@ -365,7 +365,7 @@ struct X9 : X8 {
// CHECK: Keyword: "int" [101:47 - 101:50] TypedefDecl=int_ptr_type:101:62 (Definition)
// CHECK: Punctuation: ">" [101:50 - 101:51] TypedefDecl=int_ptr_type:101:62 (Definition)
// CHECK: Punctuation: "::" [101:51 - 101:53] TypedefDecl=int_ptr_type:101:62 (Definition)
-// CHECK: Identifier: "iterator" [101:53 - 101:61] TypeRef=iterator:5:18
+// CHECK: Identifier: "iterator" [101:53 - 101:61] TypeRef=outer::inner::vector<int>::iterator:5:18
// CHECK: Identifier: "int_ptr_type" [101:62 - 101:74] TypedefDecl=int_ptr_type:101:62 (Definition)
// Dependent template specialization types
@@ -376,13 +376,13 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [107:38 - 107:40] TypedefDecl=type1:107:76 (Definition)
// CHECK: Identifier: "vector" [107:40 - 107:46] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [107:46 - 107:47] TypedefDecl=type1:107:76 (Definition)
-// CHECK: Identifier: "type" [107:47 - 107:51] TypeRef=type:106:14
+// CHECK: Identifier: "type" [107:47 - 107:51] TypeRef=X6::type:106:14
// CHECK: Punctuation: ">" [107:51 - 107:52] TypedefDecl=type1:107:76 (Definition)
// CHECK: Punctuation: "::" [107:52 - 107:54] TypedefDecl=type1:107:76 (Definition)
// CHECK: Keyword: "template" [107:54 - 107:62] TypedefDecl=type1:107:76 (Definition)
// CHECK: Identifier: "rebind" [107:63 - 107:69] TypedefDecl=type1:107:76 (Definition)
// CHECK: Punctuation: "<" [107:69 - 107:70] TypedefDecl=type1:107:76 (Definition)
-// CHECK: Identifier: "type" [107:70 - 107:74] TypeRef=type:106:14
+// CHECK: Identifier: "type" [107:70 - 107:74] TypeRef=X6::type:106:14
// CHECK: Punctuation: ">" [107:74 - 107:75] TypedefDecl=type1:107:76 (Definition)
// CHECK: Identifier: "type1" [107:76 - 107:81] TypedefDecl=type1:107:76 (Definition)
@@ -394,13 +394,13 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [108:38 - 108:40] TypedefDecl=type2:108:83 (Definition)
// CHECK: Identifier: "vector" [108:40 - 108:46] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [108:46 - 108:47] TypedefDecl=type2:108:83 (Definition)
-// CHECK: Identifier: "type" [108:47 - 108:51] TypeRef=type:106:14
+// CHECK: Identifier: "type" [108:47 - 108:51] TypeRef=X6::type:106:14
// CHECK: Punctuation: ">" [108:51 - 108:52] TypedefDecl=type2:108:83 (Definition)
// CHECK: Punctuation: "::" [108:52 - 108:54] TypedefDecl=type2:108:83 (Definition)
// CHECK: Keyword: "template" [108:54 - 108:62] TypedefDecl=type2:108:83 (Definition)
// CHECK: Identifier: "rebind" [108:63 - 108:69] TypedefDecl=type2:108:83 (Definition)
// CHECK: Punctuation: "<" [108:69 - 108:70] TypedefDecl=type2:108:83 (Definition)
-// CHECK: Identifier: "type" [108:70 - 108:74] TypeRef=type:106:14
+// CHECK: Identifier: "type" [108:70 - 108:74] TypeRef=X6::type:106:14
// CHECK: Punctuation: ">" [108:74 - 108:75] TypedefDecl=type2:108:83 (Definition)
// CHECK: Punctuation: "::" [108:75 - 108:77] TypedefDecl=type2:108:83 (Definition)
// CHECK: Identifier: "other" [108:77 - 108:82] TypedefDecl=type2:108:83 (Definition)
@@ -414,13 +414,13 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [109:35 - 109:37] TypedefDecl=type3:109:73 (Definition)
// CHECK: Identifier: "vector" [109:37 - 109:43] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [109:43 - 109:44] TypedefDecl=type3:109:73 (Definition)
-// CHECK: Identifier: "type" [109:44 - 109:48] TypeRef=type:106:14
+// CHECK: Identifier: "type" [109:44 - 109:48] TypeRef=X6::type:106:14
// CHECK: Punctuation: ">" [109:48 - 109:49] TypedefDecl=type3:109:73 (Definition)
// CHECK: Punctuation: "::" [109:49 - 109:51] TypedefDecl=type3:109:73 (Definition)
// CHECK: Keyword: "template" [109:51 - 109:59] TypedefDecl=type3:109:73 (Definition)
// CHECK: Identifier: "rebind" [109:60 - 109:66] TypedefDecl=type3:109:73 (Definition)
// CHECK: Punctuation: "<" [109:66 - 109:67] TypedefDecl=type3:109:73 (Definition)
-// CHECK: Identifier: "type" [109:67 - 109:71] TypeRef=type:106:14
+// CHECK: Identifier: "type" [109:67 - 109:71] TypeRef=X6::type:106:14
// CHECK: Punctuation: ">" [109:71 - 109:72] TypedefDecl=type3:109:73 (Definition)
// CHECK: Identifier: "type3" [109:73 - 109:78] TypedefDecl=type3:109:73 (Definition)
@@ -431,13 +431,13 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [110:35 - 110:37] TypedefDecl=type4:110:80 (Definition)
// CHECK: Identifier: "vector" [110:37 - 110:43] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [110:43 - 110:44] TypedefDecl=type4:110:80 (Definition)
-// CHECK: Identifier: "type" [110:44 - 110:48] TypeRef=type:106:14
+// CHECK: Identifier: "type" [110:44 - 110:48] TypeRef=X6::type:106:14
// CHECK: Punctuation: ">" [110:48 - 110:49] TypedefDecl=type4:110:80 (Definition)
// CHECK: Punctuation: "::" [110:49 - 110:51] TypedefDecl=type4:110:80 (Definition)
// CHECK: Keyword: "template" [110:51 - 110:59] TypedefDecl=type4:110:80 (Definition)
// CHECK: Identifier: "rebind" [110:60 - 110:66] TypedefDecl=type4:110:80 (Definition)
// CHECK: Punctuation: "<" [110:66 - 110:67] TypedefDecl=type4:110:80 (Definition)
-// CHECK: Identifier: "type" [110:67 - 110:71] TypeRef=type:106:14
+// CHECK: Identifier: "type" [110:67 - 110:71] TypeRef=X6::type:106:14
// CHECK: Punctuation: ">" [110:71 - 110:72] TypedefDecl=type4:110:80 (Definition)
// CHECK: Punctuation: "::" [110:72 - 110:74] TypedefDecl=type4:110:80 (Definition)
// CHECK: Identifier: "other" [110:74 - 110:79] TypedefDecl=type4:110:80 (Definition)
@@ -451,9 +451,9 @@ struct X9 : X8 {
// CHECK: Punctuation: "::" [126:29 - 126:31] TypedefDecl=type:126:74 (Definition)
// CHECK: Identifier: "apply_meta" [126:31 - 126:41] TemplateRef=apply_meta:116:12
// CHECK: Punctuation: "<" [126:41 - 126:42] TypedefDecl=type:126:74 (Definition)
-// CHECK: Identifier: "T_type" [126:42 - 126:48] TypeRef=T_type:124:13
+// CHECK: Identifier: "T_type" [126:42 - 126:48] TypeRef=X7::T_type:124:13
// CHECK: Punctuation: "," [126:48 - 126:49] TypedefDecl=type:126:74 (Definition)
-// CHECK: Identifier: "U_type" [126:50 - 126:56] TypeRef=U_type:125:13
+// CHECK: Identifier: "U_type" [126:50 - 126:56] TypeRef=X7::U_type:125:13
// CHECK: Punctuation: "::" [126:56 - 126:58] TypedefDecl=type:126:74 (Definition)
// CHECK: Keyword: "template" [126:58 - 126:66] TypedefDecl=type:126:74 (Definition)
// CHECK: Identifier: "apply" [126:67 - 126:72] TypedefDecl=type:126:74 (Definition)
@@ -461,6 +461,6 @@ struct X9 : X8 {
// CHECK: Identifier: "type" [126:74 - 126:78] TypedefDecl=type:126:74 (Definition)
// Member access expressions
-// CHECK: Identifier: "inherited" [136:5 - 136:14] TypeRef=inherited:134:14
+// CHECK: Identifier: "inherited" [136:5 - 136:14] TypeRef=X9::inherited:134:14
// CHECK: Punctuation: "::" [136:14 - 136:16] MemberRefExpr=f:130:8
// CHECK: Identifier: "f" [136:16 - 136:17] MemberRefExpr=f:130:8
diff --git a/test/Index/comment-cplus-decls.cpp b/test/Index/comment-cplus-decls.cpp
index d4f968f5fbf0..6e32c60a2228 100644
--- a/test/Index/comment-cplus-decls.cpp
+++ b/test/Index/comment-cplus-decls.cpp
@@ -2,9 +2,15 @@
// RUN: mkdir %t
// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %s > %t/out
// RUN: FileCheck %s < %t/out
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 -std=c++98 %s > %t/98
+// RUN: FileCheck %s < %t/98
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 -std=c++11 %s > %t/11
+// RUN: FileCheck %s < %t/11
// Ensure that XML we generate is not invalid.
// RUN: FileCheck %s -check-prefix=WRONG < %t/out
+// RUN: FileCheck %s -check-prefix=WRONG < %t/98
+// RUN: FileCheck %s -check-prefix=WRONG < %t/11
// WRONG-NOT: CommentXMLInvalid
// rdar://12378714
@@ -42,7 +48,7 @@ protected:
// CHECK: <Declaration>class Test {}</Declaration>
// CHECK: <Declaration>Test() : reserved(new Test::data()) {}</Declaration>
// CHECK: <Declaration>unsigned int getID() const</Declaration>
-// CHECK: <Declaration>~Test()</Declaration>
+// CHECK: <Declaration>~Test(){{( noexcept)?}}</Declaration>
// CHECK: <Declaration>Test::data *reserved</Declaration>
@@ -96,7 +102,7 @@ namespace test0 {
friend void ns::f(int a);
};
}
-// CHECK: <Declaration>friend void f(int a)</Declaration>
+// CHECK: <Declaration>friend void ns::f(int a)</Declaration>
namespace test1 {
template <class T> struct Outer {
@@ -109,7 +115,7 @@ namespace test1 {
};
};
}
-// CHECK: <Declaration>friend void foo(T)</Declaration>
+// CHECK: <Declaration>friend void Outer&lt;T&gt;::foo(T)</Declaration>
namespace test2 {
namespace foo {
@@ -123,7 +129,7 @@ namespace test2 {
friend void ::test2::foo::Func(int x);
};
}
-// CHECK: <Declaration>friend void Func(int x)</Declaration>
+// CHECK: <Declaration>friend void ::test2::foo::Func(int x)</Declaration>
namespace test3 {
template<class T> class vector {
@@ -143,7 +149,7 @@ namespace test3 {
};
}
// CHECK: <Declaration>void f(const T &amp;t = T())</Declaration>
-// CHECK: <Declaration>friend void f(const test3::A &amp;)</Declaration>
+// CHECK: <Declaration>friend void vector&lt;A&gt;::f(const test3::A &amp;)</Declaration>
class MyClass
{
diff --git a/test/Index/complete-block-properties.m b/test/Index/complete-block-properties.m
index 4697703c8e5c..a754712e4c99 100644
--- a/test/Index/complete-block-properties.m
+++ b/test/Index/complete-block-properties.m
@@ -68,8 +68,8 @@ void noQualifierParens(NoQualifierParens *f) {
// RUN: c-index-test -code-completion-at=%s:65:6 %s | FileCheck -check-prefix=CHECK-CC2 %s
//CHECK-CC2: ObjCInstanceMethodDecl:{ResultType void (^)(void)}{TypedText blockProperty} (35)
//CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{ResultType BarBlock}{TypedText blockProperty2} (35)
-//CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText setBlockProperty2:}{Placeholder BarBlock blockProperty2} (35)
-//CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText setBlockProperty:}{Placeholder void (^)(void)blockProperty} (35)
+//CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText setBlockProperty2:}{Placeholder ^int(int *)blockProperty2} (35)
+//CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText setBlockProperty:}{Placeholder ^(void)blockProperty} (35)
@interface ClassProperties
@@ -86,3 +86,9 @@ void classBlockProperties() {
//CHECK-CC3: ObjCPropertyDecl:{ResultType void}{TypedText explicit}{LeftParen (}{RightParen )} (35)
//CHECK-CC3-NEXT: ObjCPropertyDecl:{ResultType void (^)()}{TypedText explicit}{Equal = }{Placeholder ^(void)} (38)
//CHECK-CC3-NEXT: ObjCPropertyDecl:{ResultType void}{TypedText explicitReadonly}{LeftParen (}{RightParen )} (35)
+
+void implicitSetterBlockPlaceholder(Test* test) {
+ [test setBlock: ^{}];
+}
+// RUN: c-index-test -code-completion-at=%s:91:9 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: ObjCInstanceMethodDecl:{ResultType void}{TypedText setBlocker:}{Placeholder ^Foo(int x, Foo y, FooBlock foo)blocker} (37)
diff --git a/test/Index/complete-cached-globals.cpp b/test/Index/complete-cached-globals.cpp
new file mode 100644
index 000000000000..791faf2be128
--- /dev/null
+++ b/test/Index/complete-cached-globals.cpp
@@ -0,0 +1,25 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+namespace SomeNamespace {
+ class SomeClass {
+ };
+ void SomeFunction();
+}
+
+using SomeNamespace::SomeClass;
+using SomeNamespace::SomeFunction;
+
+static void foo() {
+ return;
+}
+
+// rdar://23454249
+
+// RUN: c-index-test -code-completion-at=%s:14:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:14:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
+
+// CHECK-CC1: ClassDecl:{TypedText SomeClass} (50)
+// CHECK-CC1: FunctionDecl:{ResultType void}{TypedText SomeFunction}{LeftParen (}{RightParen )} (50)
+// CHECK-CC1-NOT: {Text SomeNamespace::}{TypedText SomeClass}
+// CHECK-CC1-NOT: {Text SomeNamespace::}{TypedText SomeFunction}
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index e3fce6bc20f8..c2b0670077a6 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -346,3 +346,54 @@ void test_Nullability(Nullability *n, A* a) {
// RUN: c-index-test -code-completion-at=%s:197:6 %s | FileCheck -check-prefix=CHECK-NULLABLE %s
// CHECK-NULLABLE: ObjCInstanceMethodDecl:{ResultType A * _Nonnull}{TypedText method:}{Placeholder (nullable A *)}
+
+// rdar://28012953
+// Code completion results should include instance methods from RootProtocol and
+// RootClass when completing a method invocation for a RootClass object because
+// RootClasses metaclass subclasses from RootClass (i.e. RootClass is actually
+// an instance of RootClass).
+
+@protocol SubRootProtocol
+
+- (void)subProtocolInstanceMethod;
+
+@end
+
+@protocol RootProtocol <SubRootProtocol>
+
+- (void)protocolInstanceMethod;
++ (void)protocolClassMethod;
+
+@end
+
+@interface RootClass <RootProtocol>
+
+- (void)instanceMethod;
++ (void)classMethod;
+
+@end
+
+@protocol RootCategoryProtocol
+
+- (void)categoryProtocolInstanceMethod;
+
+@end
+
+@interface RootClass (Cat) <RootCategoryProtocol>
+
+- (void)categoryInstanceMethod;
+
+@end
+
+void completeAllTheRootThings() {
+ [RootClass classMethod];
+}
+
+// RUN: c-index-test -code-completion-at=%s:389:14 %s | FileCheck -check-prefix=CHECK-ROOT %s
+// CHECK-ROOT: ObjCInstanceMethodDecl:{ResultType void}{TypedText categoryInstanceMethod} (35)
+// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText categoryProtocolInstanceMethod} (37)
+// CHECK-ROOT-NEXT: ObjCClassMethodDecl:{ResultType void}{TypedText classMethod} (35)
+// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText instanceMethod} (35)
+// CHECK-ROOT-NEXT: ObjCClassMethodDecl:{ResultType void}{TypedText protocolClassMethod} (37)
+// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText protocolInstanceMethod} (37)
+// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText subProtocolInstanceMethod} (37)
diff --git a/test/Index/complete-preamble.h b/test/Index/complete-preamble.h
index e696284c0964..1972c2acb568 100644
--- a/test/Index/complete-preamble.h
+++ b/test/Index/complete-preamble.h
@@ -1,6 +1,11 @@
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+
namespace std {
void wibble();
}
+#pragma clang diagnostic pop
+
namespace std {
}
diff --git a/test/Index/crash-recovery-code-complete.c b/test/Index/crash-recovery-code-complete.c
index b2a1a9b3f96b..dfb47316dc9d 100644
--- a/test/Index/crash-recovery-code-complete.c
+++ b/test/Index/crash-recovery-code-complete.c
@@ -10,5 +10,6 @@
// FIXME: Please investigate abnormal path in MemoryBuffer.
// REQUIRES: can-remove-opened-file
+// UNSUPPORTED: libstdcxx-safe-mode
#warning parsing original file
diff --git a/test/Index/crash-recovery-modules.m b/test/Index/crash-recovery-modules.m
index 3e7e8059aaaa..296416df97f2 100644
--- a/test/Index/crash-recovery-modules.m
+++ b/test/Index/crash-recovery-modules.m
@@ -4,7 +4,7 @@
// Parse the file, such that building the module will cause Clang to crash.
// RUN: not env CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source all -fmodules -fmodules-cache-path=%t -Xclang -fdisable-module-hash -I %S/Inputs/Headers -DCRASH %s > /dev/null 2> %t.err
// RUN: FileCheck < %t.err -check-prefix=CHECK-CRASH %s
-// CHECK-CRASH: crash-recovery-modules.m:16:9:{16:2-16:14}: fatal error: could not build module 'Crash'
+// CHECK-CRASH: crash-recovery-modules.m:17:9:{17:2-17:14}: fatal error: could not build module 'Crash'
// Parse the file again, without crashing, to make sure that
// subsequent parses do the right thing.
@@ -12,6 +12,7 @@
// REQUIRES: crash-recovery
// REQUIRES: shell
+// UNSUPPORTED: libstdcxx-safe-mode
@import Crash;
diff --git a/test/Index/crash-recovery-reparse.c b/test/Index/crash-recovery-reparse.c
index baa6604b5352..2e4b51a8ca4b 100644
--- a/test/Index/crash-recovery-reparse.c
+++ b/test/Index/crash-recovery-reparse.c
@@ -7,5 +7,6 @@
// CHECK-REPARSE-SOURCE-CRASH: Unable to reparse translation unit
//
// REQUIRES: crash-recovery
+// UNSUPPORTED: libstdcxx-safe-mode
#warning parsing original file
diff --git a/test/Index/crash-recovery.c b/test/Index/crash-recovery.c
index e8e84bc504dc..bf13c69eb127 100644
--- a/test/Index/crash-recovery.c
+++ b/test/Index/crash-recovery.c
@@ -4,5 +4,6 @@
// RUN: env LIBCLANG_DISABLE_CRASH_RECOVERY=1 not --crash c-index-test -test-load-source all %s
//
// REQUIRES: crash-recovery
+// UNSUPPORTED: libstdcxx-safe-mode
#pragma clang __debug crash
diff --git a/test/Index/file-refs.cpp b/test/Index/file-refs.cpp
index c5a728b434e6..a64552704884 100644
--- a/test/Index/file-refs.cpp
+++ b/test/Index/file-refs.cpp
@@ -98,7 +98,7 @@ void f() {
// RUN: -file-refs-at=%s:44:16 \
// CHECK-NEXT: CallExpr=S:35:3
// CHECK-NEXT: TypedefDecl=Cake:39:11 (Definition) =[39:11 - 39:15]
-// CHECK-NEXT: TypeRef=Cake:39:11 =[42:3 - 42:7]
-// CHECK-NEXT: TypeRef=Cake:39:11 =[44:14 - 44:18]
+// CHECK-NEXT: TypeRef=Test2::Cake:39:11 =[42:3 - 42:7]
+// CHECK-NEXT: TypeRef=Test2::Cake:39:11 =[44:14 - 44:18]
// RUN: %s | FileCheck %s
diff --git a/test/Index/get-cursor.m b/test/Index/get-cursor.m
index d321233401c8..af277d45fdf4 100644
--- a/test/Index/get-cursor.m
+++ b/test/Index/get-cursor.m
@@ -129,6 +129,31 @@ void foo3(Test3 *test3) {
}
@end
+#define NS_ENUM(_name, _type) enum _name : _type _name; enum _name : _type
+typedef NS_ENUM(TestTransparent, int) {
+ TestTransparentFirst = 0,
+ TestTransparentSecond = 1,
+};
+typedef enum TestTransparent NotTransparent;
+
+TestTransparent transparentTypedef;
+enum TestTransparent transparentUnderlying;
+NotTransparent opaqueTypedef;
+
+#define MY_ENUM(_name, _type) enum _name : _type _name##_t; enum _name : _type
+typedef MY_ENUM(TokenPaste, int) {
+ TokenPasteFirst = 0,
+};
+TokenPaste_t opaqueTypedef2;
+
+#define MY_TYPE(_name) struct _name _name; struct _name
+typedef MY_TYPE(SomeT) { int x; };
+SomeT someVar;
+
+#define MY_TYPE2(_name) struct _name *_name; struct _name
+typedef MY_TYPE2(SomeT2) { int x; };
+SomeT2 someVar2;
+
// RUN: c-index-test -cursor-at=%s:4:28 -cursor-at=%s:5:28 %s | FileCheck -check-prefix=CHECK-PROP %s
// CHECK-PROP: ObjCPropertyDecl=foo1:4:26
@@ -193,3 +218,11 @@ void foo3(Test3 *test3) {
// RUN: c-index-test -cursor-at=%s:127:8 %s | FileCheck -check-prefix=CHECK-RECEIVER-WITH-NULLABILITY %s
// RUN: c-index-test -cursor-at=%s:128:8 %s | FileCheck -check-prefix=CHECK-RECEIVER-WITH-NULLABILITY %s
// CHECK-RECEIVER-WITH-NULLABILITY: Receiver-type=ObjCId
+
+// RUN: c-index-test -cursor-at=%s:139:1 -cursor-at=%s:140:6 -cursor-at=%s:141:1 -cursor-at=%s:147:1 -cursor-at=%s:151:1 -cursor-at=%s:155:1 %s | FileCheck -check-prefix=CHECK-TRANSPARENT %s
+// CHECK-TRANSPARENT: 139:1 TypeRef=TestTransparent:133:17 (Transparent: enum TestTransparent) Extent=[139:1 - 139:16] Spelling=TestTransparent ([139:1 - 139:16])
+// CHECK-TRANSPARENT: 140:6 TypeRef=enum TestTransparent:133:17 Extent=[140:6 - 140:21] Spelling=enum TestTransparent ([140:6 - 140:21])
+// CHECK-TRANSPARENT: 141:1 TypeRef=NotTransparent:137:30 Extent=[141:1 - 141:15] Spelling=NotTransparent ([141:1 - 141:15])
+// CHECK-TRANSPARENT: 147:1 TypeRef=TokenPaste_t:144:9 Extent=[147:1 - 147:13] Spelling=TokenPaste_t ([147:1 - 147:13])
+// CHECK-TRANSPARENT: 151:1 TypeRef=SomeT:150:17 (Transparent: struct SomeT) Extent=[151:1 - 151:6] Spelling=SomeT ([151:1 - 151:6])
+// CHECK-TRANSPARENT: 155:1 TypeRef=SomeT2:154:18 Extent=[155:1 - 155:7] Spelling=SomeT2 ([155:1 - 155:7])
diff --git a/test/Index/index-decls.m b/test/Index/index-decls.m
index 7f7f11576ab8..a5368ecb0c0d 100644
--- a/test/Index/index-decls.m
+++ b/test/Index/index-decls.m
@@ -64,9 +64,9 @@ int test1() {
// CHECK: [indexDeclaration]: kind: objc-instance-method | name: setProp: | {{.*}} | loc: 7:33
// CHECK: [indexDeclaration]: kind: objc-property | name: prop | {{.*}} | loc: 7:33
-// CHECK: [indexDeclaration]: kind: objc-ivar | name: _prop | {{.*}} | loc: 11:20
// CHECK: [indexDeclaration]: kind: objc-instance-method | name: prop | {{.*}} | loc: 11:13 | {{.*}} | lexical-container: [I:10:17]
// CHECK: [indexDeclaration]: kind: objc-instance-method | name: setProp: | {{.*}} | loc: 11:13 | {{.*}} | lexical-container: [I:10:17]
+// CHECK: [indexDeclaration]: kind: objc-ivar | name: _prop | {{.*}} | loc: 11:20
// CHECK: [indexDeclaration]: kind: objc-ivar | name: _auto_prop | {{.*}} | loc: 20:33
// CHECK: [indexEntityReference]: kind: objc-ivar | name: _auto_prop | {{.*}} | loc: 25:3
diff --git a/test/Index/opencl-types.cl b/test/Index/opencl-types.cl
new file mode 100644
index 000000000000..f15bc745a80f
--- /dev/null
+++ b/test/Index/opencl-types.cl
@@ -0,0 +1,24 @@
+// RUN: c-index-test -test-print-type %s | FileCheck %s
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+
+typedef half half4 __attribute__((ext_vector_type(4)));
+typedef float float4 __attribute__((ext_vector_type(4)));
+typedef double double4 __attribute__((ext_vector_type(4)));
+
+void kernel testFloatTypes() {
+ half scalarHalf;
+ half4 vectorHalf;
+ float scalarFloat;
+ float4 vectorFloat;
+ double scalarDouble;
+ double4 vectorDouble;
+}
+
+// CHECK: VarDecl=scalarHalf:11:8 (Definition) [type=half] [typekind=Half] [isPOD=1]
+// CHECK: VarDecl=vectorHalf:12:9 (Definition) [type=half4] [typekind=Typedef] [canonicaltype=half __attribute__((ext_vector_type(4)))] [canonicaltypekind=Unexposed] [isPOD=1]
+// CHECK: VarDecl=scalarFloat:13:9 (Definition) [type=float] [typekind=Float] [isPOD=1]
+// CHECK: VarDecl=vectorFloat:14:10 (Definition) [type=float4] [typekind=Typedef] [canonicaltype=float __attribute__((ext_vector_type(4)))] [canonicaltypekind=Unexposed] [isPOD=1]
+// CHECK: VarDecl=scalarDouble:15:10 (Definition) [type=double] [typekind=Double] [isPOD=1]
+// CHECK: VarDecl=vectorDouble:16:11 (Definition) [type=double4] [typekind=Typedef] [canonicaltype=double __attribute__((ext_vector_type(4)))] [canonicaltypekind=Unexposed] [isPOD=1]
diff --git a/test/Index/overriding-ftemplate-comments.cpp b/test/Index/overriding-ftemplate-comments.cpp
index 7fc15f0b00bd..855d2691d0a2 100644
--- a/test/Index/overriding-ftemplate-comments.cpp
+++ b/test/Index/overriding-ftemplate-comments.cpp
@@ -82,5 +82,5 @@ void comment_to_html_conversion_22();
template<class CCC1, template<class CCC2, template<class CCC3, class CCC4> class QQQ> class PPP>
void comment_to_html_conversion_22();
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#v#</USR><Declaration>template &lt;class CCC1, template &lt;class CCC2, template &lt;class CCC3, class CCC4&gt;\n class QQQ&gt; class PPP&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>CCC1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>PPP</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>CCC2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>CCC3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>CCC4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#v#</USR><Declaration>template &lt;class CCC1, template &lt;class CCC2, template &lt;class CCC3, class CCC4&gt;\n class QQQ&gt; class PPP&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>CCC1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>PPP</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>CCC2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>CCC3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>CCC4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm
index d995e0eca782..824d055b16fb 100644
--- a/test/Index/overriding-method-comments.mm
+++ b/test/Index/overriding-method-comments.mm
@@ -78,7 +78,7 @@ struct Base {
void Base::foo_outofline(int RRR) {}
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="12"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>void foo_outofline(int RRR)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>RRR</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="12"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>void Base::foo_outofline(int RRR)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>RRR</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
struct Derived : public Base {
virtual void foo_pure(int PPP);
diff --git a/test/Index/pch-from-libclang.c b/test/Index/pch-from-libclang.c
new file mode 100644
index 000000000000..349fcac01eca
--- /dev/null
+++ b/test/Index/pch-from-libclang.c
@@ -0,0 +1,27 @@
+// Check that clang can use a PCH created from libclang.
+
+// FIXME: Non-darwin bots fail. Would need investigation using -module-file-info to see what is the difference in modules generated from libclang vs the compiler invocation, in those systems.
+// REQUIRES: system-darwin
+
+// RUN: %clang_cc1 -fsyntax-only %s -verify
+// RUN: c-index-test -write-pch %t.h.pch %s -fmodules -fmodules-cache-path=%t.mcp -Xclang -triple -Xclang x86_64-apple-darwin
+// RUN: %clang -fsyntax-only -include %t.h %s -Xclang -verify -fmodules -fmodules-cache-path=%t.mcp -Xclang -detailed-preprocessing-record -Xclang -triple -Xclang x86_64-apple-darwin -Xclang -fallow-pch-with-compiler-errors
+// RUN: %clang -x c-header %s -o %t.clang.h.pch -fmodules -fmodules-cache-path=%t.mcp -Xclang -detailed-preprocessing-record -Xclang -triple -Xclang x86_64-apple-darwin -Xclang -fallow-pch-with-compiler-errors -Xclang -verify
+// RUN: c-index-test -test-load-source local %s -include %t.clang.h -fmodules -fmodules-cache-path=%t.mcp -Xclang -triple -Xclang x86_64-apple-darwin | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+void some_function(undeclared_type p); // expected-error{{unknown type name}}
+
+struct S { int x; };
+
+#else
+// expected-no-diagnostics
+
+void test(struct S *s) {
+ // CHECK: [[@LINE+1]]:6: MemberRefExpr=x:[[@LINE-6]]:16
+ s->x = 0;
+}
+
+#endif
diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp
index 784733f421b4..108ba53c80b0 100644
--- a/test/Index/print-type.cpp
+++ b/test/Index/print-type.cpp
@@ -17,6 +17,7 @@ struct Bar {
Bar(outer::Foo<bool>* foo) { }
typedef int FooType;
+ using AliasType = double;
int *p;
int *f(int *p, char *x, FooType z) {
const FooType w = z;
@@ -25,7 +26,7 @@ struct Bar {
typedef double OtherType;
typedef int ArrayType[5];
Baz<int, 1, Foo> baz;
- Qux<int, char*, Foo<int>> qux;
+ Qux<int, char*, Foo<int>, FooType> qux;
};
}
@@ -87,91 +88,92 @@ auto autoTemplRefParam = templRefParam;
// CHECK: NamespaceRef=outer:1:11 [type=] [typekind=Invalid] [isPOD=0]
// CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0]
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: TypedefDecl=FooType:19:15 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: FieldDecl=p:20:8 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
-// CHECK: CXXMethod=f:21:8 (Definition) [type=int *(int *, char *, FooType){{.*}}] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int){{.*}}] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef]] [isPOD=0]
-// CHECK: ParmDecl=p:21:15 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
-// CHECK: ParmDecl=x:21:24 (Definition) [type=char *] [typekind=Pointer] [isPOD=1] [pointeetype=char] [pointeekind=Char_{{[US]}}]
-// CHECK: ParmDecl=z:21:35 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: TypeRef=FooType:19:15 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypedefDecl=FooType:19:15 (Definition) [type=outer::inner::Bar::FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypeAliasDecl=AliasType:20:9 (Definition) [type=outer::inner::Bar::AliasType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1]
+// CHECK: FieldDecl=p:21:8 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: CXXMethod=f:22:8 (Definition) [type=int *(int *, char *, outer::inner::Bar::FooType){{.*}}] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int){{.*}}] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [outer::inner::Bar::FooType] [Typedef]] [isPOD=0]
+// CHECK: ParmDecl=p:22:15 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: ParmDecl=x:22:24 (Definition) [type=char *] [typekind=Pointer] [isPOD=1] [pointeetype=char] [pointeekind=Char_{{[US]}}]
+// CHECK: ParmDecl=z:22:35 (Definition) [type=outer::inner::Bar::FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypeRef=outer::inner::Bar::FooType:19:15 [type=outer::inner::Bar::FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: VarDecl=w:22:19 (Definition) [type=const FooType] [typekind=Typedef] const [canonicaltype=const int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: TypeRef=FooType:19:15 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: UnexposedExpr=z:21:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: DeclRefExpr=z:21:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: VarDecl=w:23:19 (Definition) [type=const outer::inner::Bar::FooType] [typekind=Typedef] const [canonicaltype=const int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypeRef=outer::inner::Bar::FooType:19:15 [type=outer::inner::Bar::FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: UnexposedExpr=z:22:35 [type=outer::inner::Bar::FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: DeclRefExpr=z:22:35 [type=outer::inner::Bar::FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
-// CHECK: UnexposedExpr=p:21:15 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
-// CHECK: DeclRefExpr=p:21:15 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
-// CHECK: UnexposedExpr=z:21:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: DeclRefExpr=z:21:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: TypedefDecl=OtherType:25:18 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1]
-// CHECK: TypedefDecl=ArrayType:26:15 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1]
+// CHECK: UnexposedExpr=p:22:15 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: DeclRefExpr=p:22:15 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: UnexposedExpr=z:22:35 [type=outer::inner::Bar::FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: DeclRefExpr=z:22:35 [type=outer::inner::Bar::FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypedefDecl=OtherType:26:18 (Definition) [type=outer::inner::Bar::OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1]
+// CHECK: TypedefDecl=ArrayType:27:15 (Definition) [type=outer::inner::Bar::ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: FieldDecl=baz:27:20 (Definition) [type=Baz<int, 1, Foo>] [typekind=Unexposed] [templateargs/3= [type=int] [typekind=Int]] [canonicaltype=outer::Baz<int, 1, Foo>] [canonicaltypekind=Record] [canonicaltemplateargs/3= [type=int] [typekind=Int]] [isPOD=1]
+// CHECK: FieldDecl=baz:28:20 (Definition) [type=Baz<int, 1, Foo>] [typekind=Unexposed] [templateargs/3= [type=int] [typekind=Int]] [canonicaltype=outer::Baz<int, 1, Foo>] [canonicaltypekind=Record] [canonicaltemplateargs/3= [type=int] [typekind=Int]] [isPOD=1]
// CHECK: TemplateRef=Baz:9:8 [type=] [typekind=Invalid] [isPOD=0]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
// CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: FieldDecl=qux:28:29 (Definition) [type=Qux<int, char *, Foo<int> >] [typekind=Unexposed] [templateargs/3= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=Foo<int>] [typekind=Unexposed]] [canonicaltype=outer::Qux<int, char *, outer::Foo<int> >] [canonicaltypekind=Record] [canonicaltemplateargs/3= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=outer::Foo<int>] [typekind=Record]] [isPOD=1]
+// CHECK: FieldDecl=qux:29:38 (Definition) [type=Qux<int, char *, Foo<int>, outer::inner::Bar::FooType>] [typekind=Unexposed] [templateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=Foo<int>] [typekind=Unexposed] [type=outer::inner::Bar::FooType] [typekind=Typedef]] [canonicaltype=outer::Qux<int, char *, outer::Foo<int>, int>] [canonicaltypekind=Record] [canonicaltemplateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=outer::Foo<int>] [typekind=Record] [type=int] [typekind=Int]] [isPOD=1]
// CHECK: TemplateRef=Qux:12:8 [type=] [typekind=Invalid] [isPOD=0]
// CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: FunctionTemplate=tbar:35:3 [type=T (int)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
-// CHECK: TemplateTypeParameter=T:34:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: TypeRef=T:34:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: ParmDecl=:35:11 (Definition) [type=int] [typekind=Int] [isPOD=1]
-// CHECK: FunctionTemplate=tbar:38:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
-// CHECK: TemplateTypeParameter=T:37:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: TypeRef=T:37:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: ParmDecl=:38:11 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1]
+// CHECK: FunctionTemplate=tbar:36:3 [type=T (int)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
+// CHECK: TemplateTypeParameter=T:35:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: TypeRef=T:35:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: ParmDecl=:36:11 (Definition) [type=int] [typekind=Int] [isPOD=1]
+// CHECK: FunctionTemplate=tbar:39:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
+// CHECK: TemplateTypeParameter=T:38:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: TypeRef=T:38:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: ParmDecl=:39:11 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: FunctionTemplate=tbar:41:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
-// CHECK: TemplateTypeParameter=T:40:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: NonTypeTemplateParameter=size:40:27 (Definition) [type=int] [typekind=Int] [isPOD=1]
-// CHECK: TypeRef=T:40:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: ParmDecl=:41:11 (Definition) [type=int [size]] [typekind=DependentSizedArray] [isPOD=0]
-// CHECK: DeclRefExpr=size:40:27 [type=int] [typekind=Int] [isPOD=1]
-// CHECK: FunctionDecl=foo:43:6 (Definition) [type=void (int, int *)] [typekind=FunctionProto] [canonicaltype=void (int, int *)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [int] [Int] [int []] [IncompleteArray]] [isPOD=0]
-// CHECK: ParmDecl=i:43:14 (Definition) [type=int] [typekind=Int] [isPOD=1]
-// CHECK: ParmDecl=incomplete_array:43:21 (Definition) [type=int []] [typekind=IncompleteArray] [isPOD=1]
+// CHECK: FunctionTemplate=tbar:42:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
+// CHECK: TemplateTypeParameter=T:41:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: NonTypeTemplateParameter=size:41:27 (Definition) [type=int] [typekind=Int] [isPOD=1]
+// CHECK: TypeRef=T:41:20 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: ParmDecl=:42:11 (Definition) [type=int [size]] [typekind=DependentSizedArray] [isPOD=0]
+// CHECK: DeclRefExpr=size:41:27 [type=int] [typekind=Int] [isPOD=1]
+// CHECK: FunctionDecl=foo:44:6 (Definition) [type=void (int, int *)] [typekind=FunctionProto] [canonicaltype=void (int, int *)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [int] [Int] [int []] [IncompleteArray]] [isPOD=0]
+// CHECK: ParmDecl=i:44:14 (Definition) [type=int] [typekind=Int] [isPOD=1]
+// CHECK: ParmDecl=incomplete_array:44:21 (Definition) [type=int []] [typekind=IncompleteArray] [isPOD=1]
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: VarDecl=variable_array:43:47 (Definition) [type=int [i]] [typekind=VariableArray] [isPOD=1]
-// CHECK: DeclRefExpr=i:43:14 [type=int] [typekind=Int] [isPOD=1]
-// CHECK: StructDecl=Blob:45:8 (Definition) [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
-// CHECK: FieldDecl=i:46:7 (Definition) [type=int] [typekind=Int] [isPOD=1]
-// CHECK: VarDecl=member_pointer:49:12 (Definition) [type=int Blob::*] [typekind=MemberPointer] [isPOD=1]
-// CHECK: FunctionDecl=elaboratedNamespaceType:51:42 [type=NS::Type (const NS::Type)] [typekind=FunctionProto] [canonicaltype=NS::Type (NS::Type)] [canonicaltypekind=FunctionProto] [resulttype=NS::Type] [resulttypekind=Elaborated] [args= [const NS::Type] [Elaborated]] [isPOD=0]
-// CHECK: NamespaceRef=NS:51:11 [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: TypeRef=struct NS::Type:51:23 [type=NS::Type] [typekind=Record] [isPOD=1]
-// CHECK: ParmDecl=t:51:81 (Definition) [type=const NS::Type] [typekind=Elaborated] const [canonicaltype=const NS::Type] [canonicaltypekind=Record] [isPOD=1]
-// CHECK: VarDecl=autoI:53:6 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: VarDecl=variable_array:44:47 (Definition) [type=int [i]] [typekind=VariableArray] [isPOD=1]
+// CHECK: DeclRefExpr=i:44:14 [type=int] [typekind=Int] [isPOD=1]
+// CHECK: StructDecl=Blob:46:8 (Definition) [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
+// CHECK: FieldDecl=i:47:7 (Definition) [type=int] [typekind=Int] [isPOD=1]
+// CHECK: VarDecl=member_pointer:50:12 (Definition) [type=int Blob::*] [typekind=MemberPointer] [isPOD=1]
+// CHECK: FunctionDecl=elaboratedNamespaceType:52:42 [type=NS::Type (const NS::Type)] [typekind=FunctionProto] [canonicaltype=NS::Type (NS::Type)] [canonicaltypekind=FunctionProto] [resulttype=NS::Type] [resulttypekind=Elaborated] [args= [const NS::Type] [Elaborated]] [isPOD=0]
+// CHECK: NamespaceRef=NS:52:11 [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: TypeRef=struct NS::Type:52:23 [type=NS::Type] [typekind=Record] [isPOD=1]
+// CHECK: ParmDecl=t:52:81 (Definition) [type=const NS::Type] [typekind=Elaborated] const [canonicaltype=const NS::Type] [canonicaltypekind=Record] [isPOD=1]
+// CHECK: VarDecl=autoI:54:6 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: VarDecl=autoTbar:54:6 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: CallExpr=tbar:35:3 [type=int] [typekind=Unexposed] [canonicaltype=int] [canonicaltypekind=Int] [args= [int] [Int]] [isPOD=1]
-// CHECK: UnexposedExpr=tbar:35:3 [type=int (*)(int)] [typekind=Pointer] [canonicaltype=int (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=int (int)] [pointeekind=FunctionProto]
-// CHECK: DeclRefExpr=tbar:35:3 RefName=[54:17 - 54:21] RefName=[54:21 - 54:26] [type=int (int)] [typekind=FunctionProto] [canonicaltype=int (int)] [canonicaltypekind=FunctionProto] [isPOD=0]
+// CHECK: VarDecl=autoTbar:55:6 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: CallExpr=tbar:36:3 [type=int] [typekind=Unexposed] [canonicaltype=int] [canonicaltypekind=Int] [args= [int] [Int]] [isPOD=1]
+// CHECK: UnexposedExpr=tbar:36:3 [type=int (*)(int)] [typekind=Pointer] [canonicaltype=int (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=int (int)] [pointeekind=FunctionProto]
+// CHECK: DeclRefExpr=tbar:36:3 RefName=[55:17 - 55:21] RefName=[55:21 - 55:26] [type=int (int)] [typekind=FunctionProto] [canonicaltype=int (int)] [canonicaltypekind=FunctionProto] [isPOD=0]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: VarDecl=autoBlob:55:6 (Definition) [type=Blob *] [typekind=Auto] [canonicaltype=Blob *] [canonicaltypekind=Pointer] [isPOD=1]
+// CHECK: VarDecl=autoBlob:56:6 (Definition) [type=Blob *] [typekind=Auto] [canonicaltype=Blob *] [canonicaltypekind=Pointer] [isPOD=1]
// CHECK: CXXNewExpr= [type=Blob *] [typekind=Pointer] [isPOD=1] [pointeetype=Blob] [pointeekind=Record]
-// CHECK: TypeRef=struct Blob:45:8 [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
-// CHECK: CallExpr=Blob:45:8 [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
-// CHECK: FunctionDecl=autoFunction:56:6 (Definition) [type=int ()] [typekind=FunctionProto] [canonicaltype=int ()] [canonicaltypekind=FunctionProto] [resulttype=int] [resulttypekind=Auto] [isPOD=0]
+// CHECK: TypeRef=struct Blob:46:8 [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
+// CHECK: CallExpr=Blob:46:8 [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
+// CHECK: FunctionDecl=autoFunction:57:6 (Definition) [type=int ()] [typekind=FunctionProto] [canonicaltype=int ()] [canonicaltypekind=FunctionProto] [resulttype=int] [resulttypekind=Auto] [isPOD=0]
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: UnexposedExpr= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: VarDecl=autoInt:57:16 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: VarDecl=autoInt:58:16 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: TypeAliasTemplateDecl=TypeAlias:60:1 (Definition) [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: TemplateTypeParameter=T:59:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: FieldDecl=foo:62:39 (Definition) [type=TypeAlias<int>] [typekind=Unexposed] [templateargs/1= [type=int] [typekind=Int]] [canonicaltype=outer::Qux<int>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=int] [typekind=Int]] [isPOD=1]
-// CHECK: TemplateRef=TypeAlias:60:1 [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: ClassTemplate=Specialization:65:8 (Definition) [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: TemplateTypeParameter=T:64:19 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: StructDecl=Specialization:68:8 [Specialization of Specialization:65:8] [type=Specialization<int>] [typekind=Record] [templateargs/1= [type=int] [typekind=Int]] [isPOD=0]
-// CHECK: VarDecl=templRefParam:70:40 (Definition) [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
-// CHECK: TemplateRef=Specialization:65:8 [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: CallExpr=Specialization:65:8 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
-// CHECK: VarDecl=autoTemplRefParam:71:6 (Definition) [type=Specialization<Specialization<bool> &>] [typekind=Auto] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
-// CHECK: UnexposedExpr=templRefParam:70:40 [type=const Specialization<Specialization<bool> &>] [typekind=Unexposed] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=const Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
-// CHECK: DeclRefExpr=templRefParam:70:40 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
+// CHECK: TypeAliasTemplateDecl=TypeAlias:61:1 (Definition) [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: TemplateTypeParameter=T:60:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: FieldDecl=foo:63:39 (Definition) [type=TypeAlias<int>] [typekind=Unexposed] [templateargs/1= [type=int] [typekind=Int]] [canonicaltype=outer::Qux<int>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=int] [typekind=Int]] [isPOD=1]
+// CHECK: TemplateRef=TypeAlias:61:1 [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: ClassTemplate=Specialization:66:8 (Definition) [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: TemplateTypeParameter=T:65:19 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: StructDecl=Specialization:69:8 [Specialization of Specialization:66:8] [type=Specialization<int>] [typekind=Record] [templateargs/1= [type=int] [typekind=Int]] [isPOD=0]
+// CHECK: VarDecl=templRefParam:71:40 (Definition) [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
+// CHECK: TemplateRef=Specialization:66:8 [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: CallExpr=Specialization:66:8 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
+// CHECK: VarDecl=autoTemplRefParam:72:6 (Definition) [type=Specialization<Specialization<bool> &>] [typekind=Auto] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
+// CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization<Specialization<bool> &>] [typekind=Unexposed] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=const Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
+// CHECK: DeclRefExpr=templRefParam:71:40 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
diff --git a/test/Index/recursive-cxx-member-calls.cpp b/test/Index/recursive-cxx-member-calls.cpp
index 36d617f48b09..9dd2d67254f2 100644
--- a/test/Index/recursive-cxx-member-calls.cpp
+++ b/test/Index/recursive-cxx-member-calls.cpp
@@ -536,7 +536,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ")" [49:73 - 49:74] CXXConstructor=StringRef:49:3 (Definition)
// CHECK-tokens: Punctuation: "{" [49:75 - 49:76] CompoundStmt=
// CHECK-tokens: Punctuation: "}" [49:76 - 49:77] CompoundStmt=
-// CHECK-tokens: Identifier: "iterator" [50:3 - 50:11] TypeRef=iterator:40:23
+// CHECK-tokens: Identifier: "iterator" [50:3 - 50:11] TypeRef=llvm::StringRef::iterator:40:23
// CHECK-tokens: Identifier: "end" [50:12 - 50:15] CXXMethod=end:50:12 (Definition)
// CHECK-tokens: Punctuation: "(" [50:15 - 50:16] CXXMethod=end:50:12 (Definition)
// CHECK-tokens: Punctuation: ")" [50:16 - 50:17] CXXMethod=end:50:12 (Definition)
@@ -1681,7 +1681,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 49:67: DeclRefExpr=length:49:38 Extent=[49:67 - 49:73]
// CHECK: 49:75: CompoundStmt= Extent=[49:75 - 49:77]
// CHECK: 50:12: CXXMethod=end:50:12 (Definition) (const) Extent=[50:3 - 50:40] [access=public]
-// CHECK: 50:3: TypeRef=iterator:40:23 Extent=[50:3 - 50:11]
+// CHECK: 50:3: TypeRef=llvm::StringRef::iterator:40:23 Extent=[50:3 - 50:11]
// CHECK: 50:24: CompoundStmt= Extent=[50:24 - 50:40]
// CHECK: 50:26: ReturnStmt= Extent=[50:26 - 50:37]
// CHECK: 50:33: MemberRefExpr=Data:43:15 Extent=[50:33 - 50:37]
diff --git a/test/Layout/ms-x86-basic-layout.cpp b/test/Layout/ms-x86-basic-layout.cpp
index c39e6ce140b4..46752a730b89 100644
--- a/test/Layout/ms-x86-basic-layout.cpp
+++ b/test/Layout/ms-x86-basic-layout.cpp
@@ -807,12 +807,12 @@ struct RecordArrayTypedef {
// CHECK: *** Dumping AST Record Layout
// CHECK-NEXT: 0 | struct RecordArrayTypedef
-// CHECK-NEXT: 0 | ArrayTy [2] InlineElts
+// CHECK-NEXT: 0 | RecordArrayTypedef::ArrayTy [2] InlineElts
// CHECK-NEXT: | [sizeof=16, align=4
// CHECK-NEXT: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct RecordArrayTypedef
-// CHECK-X64-NEXT: 0 | ArrayTy [2] InlineElts
+// CHECK-X64-NEXT: 0 | RecordArrayTypedef::ArrayTy [2] InlineElts
// CHECK-X64-NEXT: | [sizeof=16, align=4
// CHECK-X64-NEXT: | nvsize=16, nvalign=4]
diff --git a/test/Lexer/asm-preproc-no-unicode.s b/test/Lexer/asm-preproc-no-unicode.s
new file mode 100644
index 000000000000..d194a52fec3e
--- /dev/null
+++ b/test/Lexer/asm-preproc-no-unicode.s
@@ -0,0 +1,8 @@
+// RUN: %clang -E -xassembler-with-cpp %s -o - 2>&1 | FileCheck %s
+
+// CHECK-NOT: warning: \u used with no following hex digits
+// CHECK: .word \u
+
+ .macro foo, u
+ .word \u
+ .endm
diff --git a/test/Lexer/case-insensitive-include-pr31836.sh b/test/Lexer/case-insensitive-include-pr31836.sh
new file mode 100755
index 000000000000..a419f26faf8f
--- /dev/null
+++ b/test/Lexer/case-insensitive-include-pr31836.sh
@@ -0,0 +1,9 @@
+// REQUIRES: case-insensitive-filesystem
+// UNSUPPORTED: system-windows
+
+// RUN: mkdir -p %T
+// RUN: touch %T/case-insensitive-include-pr31836.h
+// RUN: echo "#include \"%T/Case-Insensitive-Include-Pr31836.h\"" | %clang_cc1 -E - 2>&1 | FileCheck %s
+
+// CHECK: warning: non-portable path to file
+// CHECK-SAME: /case-insensitive-include-pr31836.h
diff --git a/test/Lexer/cxx-features.cpp b/test/Lexer/cxx-features.cpp
index 5fc1722e942b..d69ef08a59ed 100644
--- a/test/Lexer/cxx-features.cpp
+++ b/test/Lexer/cxx-features.cpp
@@ -50,7 +50,7 @@
#error "wrong value for __cpp_capture_star_this"
#endif
-// FIXME: bump __cpp_constexpr to 201603 for constexpr lambda support
+// constexpr checked below
#if check(if_constexpr, 0, 0, 0, 201606) // FIXME: provisional name
#error "wrong value for __cpp_if_constexpr"
@@ -92,6 +92,14 @@
#error "wrong value for __cpp_nontype_template_args"
#endif
+#if check(template_template_args, 0, 0, 0, 0) // FIXME: should be 201611 when feature is enabled
+#error "wrong value for __cpp_template_template_args"
+#endif
+
+#if check(deduction_guides, 0, 0, 0, 201611) // FIXME: provisional name
+#error "wrong value for __cpp_deduction_guides"
+#endif
+
// --- C++14 features ---
#if check(binary_literals, 0, 0, 201304, 201304)
@@ -159,7 +167,7 @@
#error "wrong value for __cpp_lambdas"
#endif
-#if check(constexpr, 0, 200704, 201304, 201304)
+#if check(constexpr, 0, 200704, 201304, 201603)
#error "wrong value for __cpp_constexpr"
#endif
diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp
index e0575cb18d89..07f91605e71c 100644
--- a/test/Misc/ast-dump-attr.cpp
+++ b/test/Misc/ast-dump-attr.cpp
@@ -154,3 +154,50 @@ void f() {
struct __attribute__((objc_bridge_related(NSParagraphStyle,,))) TestBridgedRef;
// CHECK: CXXRecordDecl{{.*}} struct TestBridgedRef
// CHECK-NEXT: ObjCBridgeRelatedAttr{{.*}} NSParagraphStyle
+
+void TestExternalSourceSymbolAttr1()
+__attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration)));
+// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr1
+// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration
+
+void TestExternalSourceSymbolAttr2()
+__attribute__((external_source_symbol(defined_in="module", language="Swift")));
+// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr2
+// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module"{{$}}
+
+void TestExternalSourceSymbolAttr3()
+__attribute__((external_source_symbol(generated_declaration, language="Objective-C++", defined_in="module")));
+// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr3
+// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Objective-C++" "module" GeneratedDeclaration
+
+void TestExternalSourceSymbolAttr4()
+__attribute__((external_source_symbol(defined_in="Some external file.cs", generated_declaration, language="C Sharp")));
+// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr4
+// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "C Sharp" "Some external file.cs" GeneratedDeclaration
+
+void TestExternalSourceSymbolAttr5()
+__attribute__((external_source_symbol(generated_declaration, defined_in="module", language="Swift")));
+// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr5
+// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration
+
+namespace TestSuppress {
+ [[gsl::suppress("at-namespace")]];
+ // CHECK: NamespaceDecl{{.*}} TestSuppress
+ // CHECK-NEXT: EmptyDecl{{.*}}
+ // CHECK-NEXT: SuppressAttr{{.*}} at-namespace
+ [[gsl::suppress("on-decl")]]
+ void TestSuppressFunction();
+ // CHECK: FunctionDecl{{.*}} TestSuppressFunction
+ // CHECK-NEXT SuppressAttr{{.*}} on-decl
+
+ void f() {
+ int *i;
+
+ [[gsl::suppress("on-stmt")]] {
+ // CHECK: AttributedStmt
+ // CHECK-NEXT: SuppressAttr{{.*}} on-stmt
+ // CHECK-NEXT: CompoundStmt
+ i = reinterpret_cast<int*>(7);
+ }
+ }
+}
diff --git a/test/Misc/ast-dump-decl.cpp b/test/Misc/ast-dump-decl.cpp
index c966e133eb5d..e1cdeb0995fa 100644
--- a/test/Misc/ast-dump-decl.cpp
+++ b/test/Misc/ast-dump-decl.cpp
@@ -355,8 +355,8 @@ namespace TestTemplateTypeParmDecl {
}
// CHECK: NamespaceDecl{{.*}} TestTemplateTypeParmDecl
// CHECK-NEXT: FunctionTemplateDecl
-// CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename ... T
-// CHECK-NEXT: TemplateTypeParmDecl{{.*}} class U
+// CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename depth 0 index 0 ... T
+// CHECK-NEXT: TemplateTypeParmDecl{{.*}} class depth 0 index 1 U
// CHECK-NEXT: TemplateArgument type 'int'
namespace TestNonTypeTemplateParmDecl {
@@ -364,10 +364,10 @@ namespace TestNonTypeTemplateParmDecl {
}
// CHECK: NamespaceDecl{{.*}} TestNonTypeTemplateParmDecl
// CHECK-NEXT: FunctionTemplateDecl
-// CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' I
+// CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' depth 0 index 0 I
// CHECK-NEXT: TemplateArgument expr
// CHECK-NEXT: IntegerLiteral{{.*}} 'int' 1
-// CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' ... J
+// CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' depth 0 index 1 ... J
namespace TestTemplateTemplateParmDecl {
template<typename T> class A;
diff --git a/test/Misc/ast-dump-decl.m b/test/Misc/ast-dump-decl.m
index 539923b2e36a..4cfb8aa0c41d 100644
--- a/test/Misc/ast-dump-decl.m
+++ b/test/Misc/ast-dump-decl.m
@@ -77,7 +77,7 @@
@end
// CHECK: ObjCCategoryDecl{{.*}} TestObjCCategoryDecl
// CHECK-NEXT: ObjCInterface{{.*}} 'TestObjCClass'
-// CHECK-NEXT: ObjCCategoryImpl{{.*}} 'TestObjCClass'
+// CHECK-NEXT: ObjCCategoryImpl{{.*}} 'TestObjCCategoryDecl'
// CHECK-NEXT: ObjCProtocol{{.*}} 'P'
// CHECK-NEXT: ObjCMethodDecl{{.*}} bar
@@ -85,7 +85,7 @@
- (void) bar {
}
@end
-// CHECK: ObjCCategoryImplDecl{{.*}} TestObjCClass
+// CHECK: ObjCCategoryImplDecl{{.*}} TestObjCCategoryDecl
// CHECK-NEXT: ObjCInterface{{.*}} 'TestObjCClass'
// CHECK-NEXT: ObjCCategory{{.*}} 'TestObjCCategoryDecl'
// CHECK-NEXT: ObjCMethodDecl{{.*}} bar
diff --git a/test/Misc/ast-dump-templates.cpp b/test/Misc/ast-dump-templates.cpp
index eb493b427765..89feee75268a 100644
--- a/test/Misc/ast-dump-templates.cpp
+++ b/test/Misc/ast-dump-templates.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -ast-print %s > %t
+// RUN: %clang_cc1 -std=c++1z -ast-print %s > %t
// RUN: FileCheck < %t %s -check-prefix=CHECK1
// RUN: FileCheck < %t %s -check-prefix=CHECK2
-// RUN: %clang_cc1 -ast-dump %s | FileCheck --check-prefix=DUMP %s
+// RUN: %clang_cc1 -std=c++1z -ast-dump %s | FileCheck --check-prefix=DUMP %s
template <int X, typename Y, int Z = 5>
struct foo {
@@ -61,3 +61,9 @@ void tmpl() {
// DUMP: UnresolvedLookupExpr {{.*}} <col:3> '<overloaded function type>' lvalue (ADL) = 'func'
}
+
+namespace test3 {
+ template<typename T> struct A {};
+ template<typename T> A(T) -> A<int>;
+ // CHECK1: template <typename T> A(T) -> A<int>;
+}
diff --git a/test/Misc/ast-print-out-of-line-func.cpp b/test/Misc/ast-print-out-of-line-func.cpp
new file mode 100644
index 000000000000..7c4f7ae7f813
--- /dev/null
+++ b/test/Misc/ast-print-out-of-line-func.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -ast-print -std=c++14 %s | FileCheck %s
+
+namespace ns {
+
+struct Wrapper {
+class Inner {
+ Inner();
+ Inner(int);
+ ~Inner();
+
+ void operator += (int);
+
+ template<typename T>
+ void member();
+
+ static void staticMember();
+
+ operator int();
+
+ operator ns::Wrapper();
+ // CHECK: operator ns::Wrapper()
+};
+};
+
+Wrapper::Inner::Inner() { }
+// CHECK: Wrapper::Inner::Inner()
+
+void Wrapper::Inner::operator +=(int) { }
+// CHECK: void Wrapper::Inner::operator+=(int)
+
+}
+
+ns::Wrapper::Inner::Inner(int) { }
+// CHECK: ns::Wrapper::Inner::Inner(int)
+
+ns::Wrapper::Inner::~Inner() { }
+// CHECK: ns::Wrapper::Inner::~Inner()
+
+template<typename T>
+void ::ns::Wrapper::Inner::member() { }
+// CHECK: template <typename T> void ::ns::Wrapper::Inner::member()
+
+ns::Wrapper::Inner::operator int() { return 0; }
+// CHECK: ns::Wrapper::Inner::operator int()
+
+ns::Wrapper::Inner::operator ::ns::Wrapper() { return ns::Wrapper(); }
+// CHECK: ns::Wrapper::Inner::operator ::ns::Wrapper()
+
+namespace ns {
+
+void Wrapper::Inner::staticMember() { }
+// CHECK: void Wrapper::Inner::staticMember()
+
+}
diff --git a/test/Misc/backend-stack-frame-diagnostics.cpp b/test/Misc/backend-stack-frame-diagnostics.cpp
index a850f2253959..bb5566f1a431 100644
--- a/test/Misc/backend-stack-frame-diagnostics.cpp
+++ b/test/Misc/backend-stack-frame-diagnostics.cpp
@@ -8,7 +8,7 @@
// Test that link invocations don't emit an "argument unused during compilation" diagnostic.
// RUN: touch %t.o
-// RUN: %clang -Werror -Wno-liblto -Wframe-larger-than=0 %t.o -### 2>&1 | not grep ' error: '
+// RUN: %clang -Werror -Wno-msvc-not-found -Wno-liblto -Wframe-larger-than=0 %t.o -### 2>&1 | not grep ' error: '
// TODO: Support rich backend diagnostics for Objective-C methods.
diff --git a/test/Misc/diag-template-diffing.cpp b/test/Misc/diag-template-diffing.cpp
index 9006fc6f9ac9..174a9693f3b7 100644
--- a/test/Misc/diag-template-diffing.cpp
+++ b/test/Misc/diag-template-diffing.cpp
@@ -24,17 +24,17 @@ namespace std {
}
} // end namespace std
// CHECK-ELIDE-NOTREE: no matching function for call to 'f'
-// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<std::basic_string>' to 'vector<versa_string>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<std::string>' to 'vector<string>' for 1st argument
// CHECK-NOELIDE-NOTREE: no matching function for call to 'f'
-// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<std::basic_string>' to 'vector<versa_string>' for 1st argument
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<std::string>' to 'vector<string>' for 1st argument
// CHECK-ELIDE-TREE: no matching function for call to 'f'
// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
// CHECK-ELIDE-TREE: vector<
-// CHECK-ELIDE-TREE: [std::basic_string != versa_string]>
+// CHECK-ELIDE-TREE: [std::string != string]>
// CHECK-NOELIDE-TREE: no matching function for call to 'f'
// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
// CHECK-NOELIDE-TREE: vector<
-// CHECK-NOELIDE-TREE: [std::basic_string != versa_string]>
+// CHECK-NOELIDE-TREE: [std::string != string]>
template <int... A>
class I1{};
diff --git a/test/Modules/ExtDebugInfo.cpp b/test/Modules/ExtDebugInfo.cpp
index c39bce950664..3bd58a3da551 100644
--- a/test/Modules/ExtDebugInfo.cpp
+++ b/test/Modules/ExtDebugInfo.cpp
@@ -16,7 +16,7 @@
// RUN: %clang_cc1 -std=c++11 -debug-info-kind=standalone \
// RUN: -dwarf-ext-refs -fmodule-format=obj \
// RUN: -triple %itanium_abi_triple \
-// RUN: -include-pch %t.pch %s -emit-llvm -o %t-pch.ll %s
+// RUN: -include-pch %t.pch %s -emit-llvm -o %t-pch.ll
// RUN: cat %t-pch.ll | FileCheck %s
// RUN: cat %t-pch.ll | FileCheck %s --check-prefix=CHECK-PCH
diff --git a/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/Headers/B.h b/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/Headers/B.h
new file mode 100644
index 000000000000..761540b09cb3
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/Headers/B.h
@@ -0,0 +1 @@
+// B.h
diff --git a/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/Headers/Sub.h b/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/Headers/Sub.h
new file mode 100644
index 000000000000..fd86e3cf872f
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/Headers/Sub.h
@@ -0,0 +1,2 @@
+// Sub.h
+#import "B.h"
diff --git a/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/PrivateHeaders/BPriv.h b/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/PrivateHeaders/BPriv.h
new file mode 100644
index 000000000000..4ab49b798c63
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/PrivateHeaders/BPriv.h
@@ -0,0 +1 @@
+// BPriv.h
diff --git a/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h b/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h
new file mode 100644
index 000000000000..f6ac6188d65f
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h
@@ -0,0 +1 @@
+#import "BPriv.h"
diff --git a/test/Modules/Inputs/Main.framework/Headers/A.h b/test/Modules/Inputs/Main.framework/Headers/A.h
new file mode 100644
index 000000000000..975f1f0437bb
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/Headers/A.h
@@ -0,0 +1 @@
+// A.h
diff --git a/test/Modules/Inputs/Main.framework/Headers/Main.h b/test/Modules/Inputs/Main.framework/Headers/Main.h
new file mode 100644
index 000000000000..cb8cc00a0c45
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/Headers/Main.h
@@ -0,0 +1,2 @@
+// Main.h
+#import "A.h"
diff --git a/test/Modules/Inputs/Main.framework/Modules/module.modulemap b/test/Modules/Inputs/Main.framework/Modules/module.modulemap
new file mode 100644
index 000000000000..9fab5d350fea
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/Modules/module.modulemap
@@ -0,0 +1,12 @@
+framework module Main {
+ umbrella header "Main.h"
+
+ module * { export * }
+ export *
+
+ framework module Sub {
+ umbrella header "Sub.h"
+ module * { export * }
+ export *
+ }
+}
diff --git a/test/Modules/Inputs/Main.framework/Modules/module.private.modulemap b/test/Modules/Inputs/Main.framework/Modules/module.private.modulemap
new file mode 100644
index 000000000000..54e8be79bfa5
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/Modules/module.private.modulemap
@@ -0,0 +1,11 @@
+module Main.Private {
+ umbrella header "MainPriv.h"
+ module * { export * }
+ export *
+}
+
+module Main.Sub.Private {
+ umbrella header "SubPriv.h"
+ module * { export * }
+ export *
+}
diff --git a/test/Modules/Inputs/Main.framework/PrivateHeaders/APriv.h b/test/Modules/Inputs/Main.framework/PrivateHeaders/APriv.h
new file mode 100644
index 000000000000..6ac683c39c55
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/PrivateHeaders/APriv.h
@@ -0,0 +1 @@
+// APriv.h
diff --git a/test/Modules/Inputs/Main.framework/PrivateHeaders/MainPriv.h b/test/Modules/Inputs/Main.framework/PrivateHeaders/MainPriv.h
new file mode 100644
index 000000000000..68103017ad0b
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/PrivateHeaders/MainPriv.h
@@ -0,0 +1 @@
+#import "APriv.h"
diff --git a/test/Modules/Inputs/anon-redecl/a.h b/test/Modules/Inputs/anon-redecl/a.h
new file mode 100644
index 000000000000..1b23e724160a
--- /dev/null
+++ b/test/Modules/Inputs/anon-redecl/a.h
@@ -0,0 +1,2 @@
+struct X { union { int n; }; };
+inline int a(X x) { return x.n; }
diff --git a/test/Modules/Inputs/anon-redecl/b.h b/test/Modules/Inputs/anon-redecl/b.h
new file mode 100644
index 000000000000..23ea804a2459
--- /dev/null
+++ b/test/Modules/Inputs/anon-redecl/b.h
@@ -0,0 +1,2 @@
+struct X { union { int n; }; };
+inline int b(X x) { return x.n; }
diff --git a/test/Modules/Inputs/anon-redecl/c1.h b/test/Modules/Inputs/anon-redecl/c1.h
new file mode 100644
index 000000000000..600af314ec35
--- /dev/null
+++ b/test/Modules/Inputs/anon-redecl/c1.h
@@ -0,0 +1,2 @@
+#include "a.h"
+#include "b.h"
diff --git a/test/Modules/Inputs/anon-redecl/c2.h b/test/Modules/Inputs/anon-redecl/c2.h
new file mode 100644
index 000000000000..2e99b27194c8
--- /dev/null
+++ b/test/Modules/Inputs/anon-redecl/c2.h
@@ -0,0 +1,2 @@
+struct X { union { int n; }; };
+inline int c(X x) { return x.n; }
diff --git a/test/Modules/Inputs/anon-redecl/module.modulemap b/test/Modules/Inputs/anon-redecl/module.modulemap
new file mode 100644
index 000000000000..49678452e0c4
--- /dev/null
+++ b/test/Modules/Inputs/anon-redecl/module.modulemap
@@ -0,0 +1,6 @@
+module a { header "a.h" }
+module b { header "b.h" }
+module c {
+ module c1 { header "c1.h" }
+ module c2 { header "c2.h" }
+}
diff --git a/test/Modules/Inputs/category_right_sub.h b/test/Modules/Inputs/category_right_sub.h
index 231f65ffe0ad..c8ba7937f561 100644
--- a/test/Modules/Inputs/category_right_sub.h
+++ b/test/Modules/Inputs/category_right_sub.h
@@ -15,3 +15,8 @@
@interface Foo(LeftP4) <P4>
@end
+
+// A hidden extension
+@interface Foo ()
+@property (assign) int hiddenPropertyFromExtension;
+@end
diff --git a/test/Modules/Inputs/codegen-flags/foo.h b/test/Modules/Inputs/codegen-flags/foo.h
new file mode 100644
index 000000000000..7b9c1cd8e086
--- /dev/null
+++ b/test/Modules/Inputs/codegen-flags/foo.h
@@ -0,0 +1,4 @@
+struct foo {
+};
+inline void f1() {
+}
diff --git a/test/Modules/Inputs/codegen-flags/foo.modulemap b/test/Modules/Inputs/codegen-flags/foo.modulemap
new file mode 100644
index 000000000000..2e095d2794c3
--- /dev/null
+++ b/test/Modules/Inputs/codegen-flags/foo.modulemap
@@ -0,0 +1 @@
+module foo { header "foo.h" }
diff --git a/test/Modules/Inputs/codegen-flags/use.cpp b/test/Modules/Inputs/codegen-flags/use.cpp
new file mode 100644
index 000000000000..378ff3124e75
--- /dev/null
+++ b/test/Modules/Inputs/codegen-flags/use.cpp
@@ -0,0 +1,5 @@
+#include "foo.h"
+void use() {
+ f1();
+ foo f;
+}
diff --git a/test/Modules/Inputs/codegen-nodep/foo.h b/test/Modules/Inputs/codegen-nodep/foo.h
new file mode 100644
index 000000000000..e7b20a512db1
--- /dev/null
+++ b/test/Modules/Inputs/codegen-nodep/foo.h
@@ -0,0 +1,11 @@
+template <typename T>
+void foot() {
+}
+inline void foo() {
+}
+
+template <typename T>
+struct bart {
+};
+struct bar {
+};
diff --git a/test/Modules/Inputs/codegen-nodep/foo.modulemap b/test/Modules/Inputs/codegen-nodep/foo.modulemap
new file mode 100644
index 000000000000..2e095d2794c3
--- /dev/null
+++ b/test/Modules/Inputs/codegen-nodep/foo.modulemap
@@ -0,0 +1 @@
+module foo { header "foo.h" }
diff --git a/test/Modules/Inputs/codegen-opt/bar.h b/test/Modules/Inputs/codegen-opt/bar.h
new file mode 100644
index 000000000000..a00e8f70e089
--- /dev/null
+++ b/test/Modules/Inputs/codegen-opt/bar.h
@@ -0,0 +1,2 @@
+#include "foo.h"
+inline void bar() { foo(); }
diff --git a/test/Modules/Inputs/codegen-opt/bar.modulemap b/test/Modules/Inputs/codegen-opt/bar.modulemap
new file mode 100644
index 000000000000..f1dc625857e0
--- /dev/null
+++ b/test/Modules/Inputs/codegen-opt/bar.modulemap
@@ -0,0 +1 @@
+module bar { header "bar.h" }
diff --git a/test/Modules/Inputs/codegen-opt/foo.h b/test/Modules/Inputs/codegen-opt/foo.h
new file mode 100644
index 000000000000..b3a7af7c9d9b
--- /dev/null
+++ b/test/Modules/Inputs/codegen-opt/foo.h
@@ -0,0 +1,10 @@
+void f1(int &);
+static void f2() {}
+inline void foo() {
+ static int i;
+ f1(i);
+ f2();
+}
+inline void foo2() {
+}
+void foo_ext() {}
diff --git a/test/Modules/Inputs/codegen-opt/foo.modulemap b/test/Modules/Inputs/codegen-opt/foo.modulemap
new file mode 100644
index 000000000000..2e095d2794c3
--- /dev/null
+++ b/test/Modules/Inputs/codegen-opt/foo.modulemap
@@ -0,0 +1 @@
+module foo { header "foo.h" }
diff --git a/test/Modules/Inputs/codegen-opt/use.cpp b/test/Modules/Inputs/codegen-opt/use.cpp
new file mode 100644
index 000000000000..b55a31fe158f
--- /dev/null
+++ b/test/Modules/Inputs/codegen-opt/use.cpp
@@ -0,0 +1,2 @@
+#include "bar.h"
+int main() { bar(); }
diff --git a/test/Modules/Inputs/codegen/foo.h b/test/Modules/Inputs/codegen/foo.h
new file mode 100644
index 000000000000..bd3b6489e710
--- /dev/null
+++ b/test/Modules/Inputs/codegen/foo.h
@@ -0,0 +1,32 @@
+inline void f1(const char* fmt, ...) {
+ __builtin_va_list args;
+ __builtin_va_start(args, fmt);
+}
+
+struct non_trivial_dtor {
+ ~non_trivial_dtor();
+};
+
+struct implicit_dtor {
+ non_trivial_dtor d;
+};
+
+struct uninst_implicit_dtor {
+ non_trivial_dtor d;
+};
+
+inline void use_implicit_dtor() {
+ implicit_dtor d;
+}
+
+template <typename T>
+void inst() {
+}
+
+inline void inst_decl() {
+ // cause inst<int>'s declaration to be instantiated, without a definition.
+ (void)sizeof(&inst<int>);
+ inst<float>();
+}
+
+asm("narf");
diff --git a/test/Modules/Inputs/codegen/foo.modulemap b/test/Modules/Inputs/codegen/foo.modulemap
new file mode 100644
index 000000000000..2e095d2794c3
--- /dev/null
+++ b/test/Modules/Inputs/codegen/foo.modulemap
@@ -0,0 +1 @@
+module foo { header "foo.h" }
diff --git a/test/Modules/Inputs/codegen/use.cpp b/test/Modules/Inputs/codegen/use.cpp
new file mode 100644
index 000000000000..cd1a4a642d09
--- /dev/null
+++ b/test/Modules/Inputs/codegen/use.cpp
@@ -0,0 +1,8 @@
+#include "foo.h"
+void non_modular_use_of_implicit_dtor() {
+ implicit_dtor d1;
+ uninst_implicit_dtor d2;
+}
+void use_of_instantiated_declaration_without_definition() {
+ inst<int>();
+}
diff --git a/test/Modules/Inputs/cxx17/decls.h b/test/Modules/Inputs/cxx17/decls.h
new file mode 100644
index 000000000000..473b6d15112a
--- /dev/null
+++ b/test/Modules/Inputs/cxx17/decls.h
@@ -0,0 +1,3 @@
+struct MergeExceptionSpec {
+ ~MergeExceptionSpec(); // unevaluated exception spec
+};
diff --git a/test/Modules/Inputs/cxx17/module.modulemap b/test/Modules/Inputs/cxx17/module.modulemap
new file mode 100644
index 000000000000..2339e49e03bd
--- /dev/null
+++ b/test/Modules/Inputs/cxx17/module.modulemap
@@ -0,0 +1 @@
+module Decls { header "decls.h" }
diff --git a/test/Modules/Inputs/diag_pragma.h b/test/Modules/Inputs/diag_pragma.h
index a8f958994ca5..59c73ea756e0 100644
--- a/test/Modules/Inputs/diag_pragma.h
+++ b/test/Modules/Inputs/diag_pragma.h
@@ -1,3 +1,13 @@
#define DIAG_PRAGMA_MACRO 1
#pragma clang diagnostic ignored "-Wparentheses"
+
+#ifdef __cplusplus
+template<typename T> const char *f(T t) {
+ return "foo" + t;
+}
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+template<typename T> const char *g(T t) {
+ return "foo" + t;
+}
+#endif
diff --git a/test/Modules/Inputs/gnumode-non-benign/module.h b/test/Modules/Inputs/gnumode-non-benign/module.h
new file mode 100644
index 000000000000..efde0ad70c55
--- /dev/null
+++ b/test/Modules/Inputs/gnumode-non-benign/module.h
@@ -0,0 +1,5 @@
+// Check for GNUMode = 1 by looking for the "linux" define which only exists
+// for GNUMode = 1.
+#ifdef linux
+ #error "Submodule has GNUMode=1"
+#endif
diff --git a/test/Modules/Inputs/gnumode-non-benign/module.modulemap b/test/Modules/Inputs/gnumode-non-benign/module.modulemap
new file mode 100644
index 000000000000..702ef596eb06
--- /dev/null
+++ b/test/Modules/Inputs/gnumode-non-benign/module.modulemap
@@ -0,0 +1 @@
+module "module.h" { header "module.h"}
diff --git a/test/Modules/Inputs/hidden-names/hidden.h b/test/Modules/Inputs/hidden-names/hidden.h
new file mode 100644
index 000000000000..e5c2f551c52d
--- /dev/null
+++ b/test/Modules/Inputs/hidden-names/hidden.h
@@ -0,0 +1,3 @@
+namespace NS {
+ struct X {};
+}
diff --git a/test/Modules/Inputs/hidden-names/module.modulemap b/test/Modules/Inputs/hidden-names/module.modulemap
new file mode 100644
index 000000000000..1471f589c666
--- /dev/null
+++ b/test/Modules/Inputs/hidden-names/module.modulemap
@@ -0,0 +1,4 @@
+module hidden {
+ header "visible.h"
+ explicit module sub { header "hidden.h" }
+}
diff --git a/test/Modules/Inputs/hidden-names/visible.h b/test/Modules/Inputs/hidden-names/visible.h
new file mode 100644
index 000000000000..3dfc9c715cda
--- /dev/null
+++ b/test/Modules/Inputs/hidden-names/visible.h
@@ -0,0 +1,2 @@
+// hidden-names/visible.h
+namespace NS {}
diff --git a/test/Modules/Inputs/implicit-built-Werror-using-W/convert.h b/test/Modules/Inputs/implicit-built-Werror-using-W/convert.h
new file mode 100644
index 000000000000..0ed02bc793bd
--- /dev/null
+++ b/test/Modules/Inputs/implicit-built-Werror-using-W/convert.h
@@ -0,0 +1,8 @@
+#ifdef USE_PRAGMA
+#pragma clang diagnostic push
+#pragma clang diagnostic warning "-Wshorten-64-to-32"
+#endif
+template <class T> int convert(T V) { return V; }
+#ifdef USE_PRAGMA
+#pragma clang diagnostic pop
+#endif
diff --git a/test/Modules/Inputs/implicit-built-Werror-using-W/module.modulemap b/test/Modules/Inputs/implicit-built-Werror-using-W/module.modulemap
new file mode 100644
index 000000000000..825eb86038ed
--- /dev/null
+++ b/test/Modules/Inputs/implicit-built-Werror-using-W/module.modulemap
@@ -0,0 +1,3 @@
+module convert {
+ header "convert.h"
+}
diff --git a/test/Modules/Inputs/invalid-module-id/NC-Prefix.pch b/test/Modules/Inputs/invalid-module-id/NC-Prefix.pch
new file mode 100644
index 000000000000..73a9816a3abd
--- /dev/null
+++ b/test/Modules/Inputs/invalid-module-id/NC-Prefix.pch
@@ -0,0 +1,3 @@
+#ifdef __OBJC__
+ #import <NC/NULog.h>
+#endif
diff --git a/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NC.h b/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NC.h
new file mode 100644
index 000000000000..3866c8882821
--- /dev/null
+++ b/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NC.h
@@ -0,0 +1 @@
+#import <NC/NUGeometry.h>
diff --git a/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NU-Visibility.h b/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NU-Visibility.h
new file mode 100644
index 000000000000..1e7614c0c381
--- /dev/null
+++ b/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NU-Visibility.h
@@ -0,0 +1 @@
+// NU-Visibility.h
diff --git a/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NUGeometry.h b/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NUGeometry.h
new file mode 100644
index 000000000000..8923e042db6c
--- /dev/null
+++ b/test/Modules/Inputs/invalid-module-id/NC.framework/Headers/NUGeometry.h
@@ -0,0 +1 @@
+#import <NC/NU-Visibility.h>
diff --git a/test/Modules/Inputs/invalid-module-id/NC.framework/Modules/module.modulemap b/test/Modules/Inputs/invalid-module-id/NC.framework/Modules/module.modulemap
new file mode 100644
index 000000000000..475b41473360
--- /dev/null
+++ b/test/Modules/Inputs/invalid-module-id/NC.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module NC {
+ umbrella header "NC.h"
+
+ export *
+ module * { export * }
+}
diff --git a/test/Modules/Inputs/invalid-module-id/NC.framework/Modules/module.private.modulemap b/test/Modules/Inputs/invalid-module-id/NC.framework/Modules/module.private.modulemap
new file mode 100644
index 000000000000..80488bd5d3d1
--- /dev/null
+++ b/test/Modules/Inputs/invalid-module-id/NC.framework/Modules/module.private.modulemap
@@ -0,0 +1,5 @@
+explicit module NC.Private
+{
+ header "NULog.h"
+ header "NUAssert.h"
+}
diff --git a/test/Modules/Inputs/invalid-module-id/NC.framework/PrivateHeaders/NUAssert.h b/test/Modules/Inputs/invalid-module-id/NC.framework/PrivateHeaders/NUAssert.h
new file mode 100644
index 000000000000..7bf8defa8ccb
--- /dev/null
+++ b/test/Modules/Inputs/invalid-module-id/NC.framework/PrivateHeaders/NUAssert.h
@@ -0,0 +1 @@
+#import <NC/NULog.h>
diff --git a/test/Modules/Inputs/invalid-module-id/NC.framework/PrivateHeaders/NULog.h b/test/Modules/Inputs/invalid-module-id/NC.framework/PrivateHeaders/NULog.h
new file mode 100644
index 000000000000..8923e042db6c
--- /dev/null
+++ b/test/Modules/Inputs/invalid-module-id/NC.framework/PrivateHeaders/NULog.h
@@ -0,0 +1 @@
+#import <NC/NU-Visibility.h>
diff --git a/test/Modules/Inputs/merge-function-defs/a.h b/test/Modules/Inputs/merge-function-defs/a.h
new file mode 100644
index 000000000000..7fc0e52c4104
--- /dev/null
+++ b/test/Modules/Inputs/merge-function-defs/a.h
@@ -0,0 +1,4 @@
+struct X {
+ virtual void f();
+};
+inline void X::f() {}
diff --git a/test/Modules/Inputs/merge-function-defs/b.h b/test/Modules/Inputs/merge-function-defs/b.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Modules/Inputs/merge-function-defs/b.h
diff --git a/test/Modules/Inputs/merge-function-defs/map b/test/Modules/Inputs/merge-function-defs/map
new file mode 100644
index 000000000000..f84c7ddfd5ad
--- /dev/null
+++ b/test/Modules/Inputs/merge-function-defs/map
@@ -0,0 +1,4 @@
+module m {
+ module a { header "a.h" }
+ module b { header "b.h" }
+}
diff --git a/test/Modules/Inputs/merge-name-for-linkage/b.h b/test/Modules/Inputs/merge-name-for-linkage/b.h
index 82f2fdd83e31..5593e4117139 100644
--- a/test/Modules/Inputs/merge-name-for-linkage/b.h
+++ b/test/Modules/Inputs/merge-name-for-linkage/b.h
@@ -1 +1,5 @@
typedef union {} pthread_mutex_t;
+
+// Define then merge with another definition.
+typedef struct {} merged_after_definition;
+#include "c1.h"
diff --git a/test/Modules/Inputs/merge-name-for-linkage/c1.h b/test/Modules/Inputs/merge-name-for-linkage/c1.h
new file mode 100644
index 000000000000..b3fd8aced6ea
--- /dev/null
+++ b/test/Modules/Inputs/merge-name-for-linkage/c1.h
@@ -0,0 +1 @@
+// c1
diff --git a/test/Modules/Inputs/merge-name-for-linkage/c2.h b/test/Modules/Inputs/merge-name-for-linkage/c2.h
new file mode 100644
index 000000000000..3ac835629915
--- /dev/null
+++ b/test/Modules/Inputs/merge-name-for-linkage/c2.h
@@ -0,0 +1,2 @@
+// c2.h
+typedef struct {} merged_after_definition;
diff --git a/test/Modules/Inputs/merge-name-for-linkage/module.modulemap b/test/Modules/Inputs/merge-name-for-linkage/module.modulemap
index 61578a1865aa..216add76be2a 100644
--- a/test/Modules/Inputs/merge-name-for-linkage/module.modulemap
+++ b/test/Modules/Inputs/merge-name-for-linkage/module.modulemap
@@ -1,2 +1,3 @@
module a { header "a.h" export * }
module b { header "b.h" export * }
+module c { module c1 { header "c1.h" export * } module c2 { header "c2.h" export * } }
diff --git a/test/Modules/Inputs/merge-using-decls/b.h b/test/Modules/Inputs/merge-using-decls/b.h
index 359555570a43..5d112ffbfe96 100644
--- a/test/Modules/Inputs/merge-using-decls/b.h
+++ b/test/Modules/Inputs/merge-using-decls/b.h
@@ -29,11 +29,13 @@ template<typename T> struct D : X, T {
using typename X::t;
};
+#if __cplusplus <= 199711L // C++11 does not allow access declarations
template<typename T> struct E : X, T {
// Mismatch in using/access-declaration-ness.
T::value;
X::v;
};
+#endif
template<typename T> struct F : X, T {
// Mismatch in nested-name-specifier.
@@ -46,5 +48,9 @@ template<typename T> struct F : X, T {
// Force instantiation.
typedef C<YB>::type I;
typedef D<YBRev>::t I;
+
+#if __cplusplus <= 199711L // C++11 does not allow access declarations
typedef E<YB>::type I;
+#endif
+
typedef F<YB>::type I;
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index 2beb942861a4..b95eec351e86 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -265,6 +265,11 @@ module diag_pragma {
header "diag_pragma.h"
}
+module pragma_pack {
+ module set { header "pragma_pack_set.h" }
+ module empty { header "empty.h" }
+}
+
module dummy {
header "dummy.h"
}
diff --git a/test/Modules/Inputs/outofdate-rebuild/AppKit.h b/test/Modules/Inputs/outofdate-rebuild/AppKit.h
new file mode 100644
index 000000000000..e357918fd45c
--- /dev/null
+++ b/test/Modules/Inputs/outofdate-rebuild/AppKit.h
@@ -0,0 +1,3 @@
+// AppKit
+#import "CoreVideo.h" // CoreVideo
+struct B { int i; };
diff --git a/test/Modules/Inputs/outofdate-rebuild/Cocoa.h b/test/Modules/Inputs/outofdate-rebuild/Cocoa.h
new file mode 100644
index 000000000000..d6311405f4e1
--- /dev/null
+++ b/test/Modules/Inputs/outofdate-rebuild/Cocoa.h
@@ -0,0 +1,5 @@
+// Cocoa
+#import "Foundation.h"
+#import "AppKit.h"
+
+struct A { int i; };
diff --git a/test/Modules/Inputs/outofdate-rebuild/CoreText.h b/test/Modules/Inputs/outofdate-rebuild/CoreText.h
new file mode 100644
index 000000000000..7ff0e23af1ba
--- /dev/null
+++ b/test/Modules/Inputs/outofdate-rebuild/CoreText.h
@@ -0,0 +1 @@
+struct C { int i; };
diff --git a/test/Modules/Inputs/outofdate-rebuild/CoreVideo.h b/test/Modules/Inputs/outofdate-rebuild/CoreVideo.h
new file mode 100644
index 000000000000..bd249dcbb74c
--- /dev/null
+++ b/test/Modules/Inputs/outofdate-rebuild/CoreVideo.h
@@ -0,0 +1,3 @@
+// CoreVideo
+#import "Foundation.h" // Foundation
+struct E { int i; };
diff --git a/test/Modules/Inputs/outofdate-rebuild/Foundation.h b/test/Modules/Inputs/outofdate-rebuild/Foundation.h
new file mode 100644
index 000000000000..b2d053ad057a
--- /dev/null
+++ b/test/Modules/Inputs/outofdate-rebuild/Foundation.h
@@ -0,0 +1,3 @@
+// Foundation
+#import "CoreText.h"
+struct D { int i; };
diff --git a/test/Modules/Inputs/outofdate-rebuild/module.modulemap b/test/Modules/Inputs/outofdate-rebuild/module.modulemap
new file mode 100644
index 000000000000..71c99e81966e
--- /dev/null
+++ b/test/Modules/Inputs/outofdate-rebuild/module.modulemap
@@ -0,0 +1,19 @@
+module Cocoa {
+ header "Cocoa.h"
+}
+
+module AppKit {
+ header "AppKit.h"
+}
+
+module CoreText {
+ header "CoreText.h"
+}
+
+module Foundation {
+ header "Foundation.h"
+}
+
+module CoreVideo {
+ header "CoreVideo.h"
+}
diff --git a/test/Modules/Inputs/overloadable-attrs/a.h b/test/Modules/Inputs/overloadable-attrs/a.h
new file mode 100644
index 000000000000..1af769dad315
--- /dev/null
+++ b/test/Modules/Inputs/overloadable-attrs/a.h
@@ -0,0 +1,28 @@
+namespace enable_if_attrs {
+constexpr int fn1() __attribute__((enable_if(0, ""))) { return 0; }
+constexpr int fn1() { return 1; }
+
+constexpr int fn2() { return 1; }
+constexpr int fn2() __attribute__((enable_if(0, ""))) { return 0; }
+
+constexpr int fn3(int i) __attribute__((enable_if(!i, ""))) { return 0; }
+constexpr int fn3(int i) __attribute__((enable_if(i, ""))) { return 1; }
+
+constexpr int fn4(int i) { return 0; }
+constexpr int fn4(int i) __attribute__((enable_if(i, ""))) { return 1; }
+
+constexpr int fn5(int i) __attribute__((enable_if(i, ""))) { return 1; }
+constexpr int fn5(int i) { return 0; }
+}
+
+namespace pass_object_size_attrs {
+constexpr int fn1(void *const a __attribute__((pass_object_size(0)))) {
+ return 1;
+}
+constexpr int fn1(void *const a) { return 0; }
+
+constexpr int fn2(void *const a) { return 0; }
+constexpr int fn2(void *const a __attribute__((pass_object_size(0)))) {
+ return 1;
+}
+}
diff --git a/test/Modules/Inputs/overloadable-attrs/module.modulemap b/test/Modules/Inputs/overloadable-attrs/module.modulemap
new file mode 100644
index 000000000000..514d745d1465
--- /dev/null
+++ b/test/Modules/Inputs/overloadable-attrs/module.modulemap
@@ -0,0 +1,3 @@
+module a {
+ header "a.h"
+}
diff --git a/test/Modules/Inputs/pragma_pack_set.h b/test/Modules/Inputs/pragma_pack_set.h
new file mode 100644
index 000000000000..b123c116ea1c
--- /dev/null
+++ b/test/Modules/Inputs/pragma_pack_set.h
@@ -0,0 +1,3 @@
+
+#pragma pack (1)
+
diff --git a/test/Modules/Inputs/system-out-of-date/X.h b/test/Modules/Inputs/system-out-of-date/X.h
new file mode 100644
index 000000000000..f26ce7e27d09
--- /dev/null
+++ b/test/Modules/Inputs/system-out-of-date/X.h
@@ -0,0 +1,2 @@
+// X.h
+#import <Y.h>
diff --git a/test/Modules/Inputs/system-out-of-date/Y.h b/test/Modules/Inputs/system-out-of-date/Y.h
new file mode 100644
index 000000000000..90fe1bcc5851
--- /dev/null
+++ b/test/Modules/Inputs/system-out-of-date/Y.h
@@ -0,0 +1 @@
+//empty
diff --git a/test/Modules/Inputs/system-out-of-date/Z.h b/test/Modules/Inputs/system-out-of-date/Z.h
new file mode 100644
index 000000000000..5db801a509de
--- /dev/null
+++ b/test/Modules/Inputs/system-out-of-date/Z.h
@@ -0,0 +1,2 @@
+// Z.h
+#import <Y.h>
diff --git a/test/Modules/Inputs/system-out-of-date/module.map b/test/Modules/Inputs/system-out-of-date/module.map
new file mode 100644
index 000000000000..0c0f42a5d01c
--- /dev/null
+++ b/test/Modules/Inputs/system-out-of-date/module.map
@@ -0,0 +1,12 @@
+module X [system] {
+ header "X.h" // imports Y
+ export *
+}
+module Y {
+ header "Y.h"
+ export *
+}
+module Z {
+ header "Z.h" // imports Y
+ export *
+}
diff --git a/test/Modules/Inputs/warning-mismatch/Mismatch.h b/test/Modules/Inputs/warning-mismatch/Mismatch.h
new file mode 100644
index 000000000000..a07b0ee31eaf
--- /dev/null
+++ b/test/Modules/Inputs/warning-mismatch/Mismatch.h
@@ -0,0 +1 @@
+struct Mismatch { int i; };
diff --git a/test/Modules/Inputs/warning-mismatch/System.h b/test/Modules/Inputs/warning-mismatch/System.h
new file mode 100644
index 000000000000..8e69e704c753
--- /dev/null
+++ b/test/Modules/Inputs/warning-mismatch/System.h
@@ -0,0 +1,2 @@
+#import "Mismatch.h"
+struct System { int i; };
diff --git a/test/Modules/Inputs/warning-mismatch/module.modulemap b/test/Modules/Inputs/warning-mismatch/module.modulemap
new file mode 100644
index 000000000000..c22cde459787
--- /dev/null
+++ b/test/Modules/Inputs/warning-mismatch/module.modulemap
@@ -0,0 +1,7 @@
+module System [system] {
+ header "System.h"
+}
+
+module Mismatch {
+ header "Mismatch.h"
+}
diff --git a/test/Modules/anon-redecl.cpp b/test/Modules/anon-redecl.cpp
new file mode 100644
index 000000000000..c3c5c9e527e4
--- /dev/null
+++ b/test/Modules/anon-redecl.cpp
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-local-submodule-visibility \
+// RUN: -fmodule-map-file=%S/Inputs/anon-redecl/module.modulemap \
+// RUN: -I%S/Inputs/anon-redecl \
+// RUN: -verify -std=c++11 %s
+
+#include "a.h"
+#include "b.h"
+#include "c1.h"
+#include "c2.h"
+
+// expected-no-diagnostics
+int x = a({});
+int y = b({});
+int z = c({});
diff --git a/test/Modules/builtins.m b/test/Modules/builtins.m
index 2480e6379cc8..88a44e7b0aa3 100644
--- a/test/Modules/builtins.m
+++ b/test/Modules/builtins.m
@@ -8,6 +8,7 @@
// RUN: %clang_cc1 -fmodules-cache-path=%t.pch.cache -fmodules -fimplicit-module-maps -I %S/Inputs %s -include-pch %t.pch %s -verify
// expected-no-diagnostics
+// REQUIRES: shell
void use_constant_string_builtins1(void) {
(void)__builtin___CFStringMakeConstantString("");
diff --git a/test/Modules/codegen-flags.test b/test/Modules/codegen-flags.test
new file mode 100644
index 000000000000..4cc62e87358d
--- /dev/null
+++ b/test/Modules/codegen-flags.test
@@ -0,0 +1,25 @@
+RUN: rm -rf %t
+REQUIRES: x86-registered-target
+
+RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen-flags/foo.modulemap -o %t/foo-cg.pcm
+RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-debuginfo -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen-flags/foo.modulemap -o %t/foo-di.pcm
+
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - %t/foo-cg.pcm | FileCheck --check-prefix=CG %s
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - %t/foo-di.pcm | FileCheck --check-prefix=DI %s
+
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - -fmodules -fmodule-file=%t/foo-cg.pcm %S/Inputs/codegen-flags/use.cpp | FileCheck --check-prefix=CG-USE %s
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - -fmodules -fmodule-file=%t/foo-di.pcm %S/Inputs/codegen-flags/use.cpp | FileCheck --check-prefix=DI-USE %s
+
+CG: define weak_odr void @_Z2f1v
+CG: DICompileUnit
+CG-NOT: DICompositeType
+
+CG-USE: declare void @_Z2f1v
+CG-USE: DICompileUnit
+CG-USE: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
+
+DI-NOT: define
+DI: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
+
+DI-USE: define linkonce_odr void @_Z2f1v
+DI-USE: = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", {{.*}}, flags: DIFlagFwdDecl
diff --git a/test/Modules/codegen-nodep.test b/test/Modules/codegen-nodep.test
new file mode 100644
index 000000000000..9b718ca9a3cf
--- /dev/null
+++ b/test/Modules/codegen-nodep.test
@@ -0,0 +1,13 @@
+RUN: rm -rf %t
+REQUIRES: x86-registered-target
+
+RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -fmodules-debuginfo \
+RUN: -x c++ -fmodules -emit-module -fmodule-name=foo \
+RUN: %S/Inputs/codegen-nodep/foo.modulemap -o - \
+RUN: | llvm-bcanalyzer - -dump \
+RUN: | FileCheck %s
+
+Ensure there are only two modular codegen decls (one for the class, one for the
+function - none for the class and function templates).
+
+CHECK: <MODULAR_CODEGEN_DECLS op0={{[0-9]+}} op1={{[0-9]+}}/>
diff --git a/test/Modules/codegen-opt.test b/test/Modules/codegen-opt.test
new file mode 100644
index 000000000000..2f4997a7c73f
--- /dev/null
+++ b/test/Modules/codegen-opt.test
@@ -0,0 +1,65 @@
+RUN: rm -rf %t
+REQUIRES: x86-registered-target
+
+RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen-opt/foo.modulemap -o %t/foo.pcm
+RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=bar %S/Inputs/codegen-opt/bar.modulemap -o %t/bar.pcm -fmodule-file=%t/foo.pcm
+
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %t/foo.pcm | FileCheck --check-prefix=FOO %s
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %t/bar.pcm -fmodule-file=%t/foo.pcm | FileCheck --check-prefix=BAR-CMN --check-prefix=BAR %s
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -fmodules -fmodule-file=%t/foo.pcm -fmodule-file=%t/bar.pcm %S/Inputs/codegen-opt/use.cpp | FileCheck --check-prefix=USE-CMN --check-prefix=USE %s
+
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -O2 -disable-llvm-passes %t/foo.pcm | FileCheck --check-prefix=FOO %s
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -O2 -disable-llvm-passes %t/bar.pcm -fmodule-file=%t/foo.pcm | FileCheck --check-prefix=BAR-CMN --check-prefix=BAR-OPT %s
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -O2 -disable-llvm-passes -fmodules -fmodule-file=%t/foo.pcm -fmodule-file=%t/bar.pcm %S/Inputs/codegen-opt/use.cpp | FileCheck --check-prefix=USE-CMN --check-prefix=USE-OPT %s
+
+FOO-NOT: comdat
+FOO: $_Z3foov = comdat any
+FOO: $_Z4foo2v = comdat any
+FOO: $_ZZ3foovE1i = comdat any
+FOO: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+FOO-NOT: {{comdat|define|declare}}
+FOO: define void @_Z7foo_extv()
+FOO-NOT: {{define|declare}}
+FOO: define weak_odr void @_Z3foov() #{{[0-9]+}} comdat
+FOO-NOT: {{define|declare}}
+FOO: declare void @_Z2f1Ri(i32*
+FOO-NOT: {{define|declare}}
+
+FIXME: this internal function should be weak_odr, comdat, and with a new mangling
+FOO: define internal void @_ZL2f2v() #{{[0-9]+}}
+FOO-NOT: {{define|declare}}
+
+FOO: define weak_odr void @_Z4foo2v() #{{[0-9]+}} comdat
+FOO-NOT: {{define|declare}}
+
+
+BAR-CMN-NOT: comdat
+BAR-CMN: $_Z3barv = comdat any
+BAR-OPT: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+BAR-CMN-NOT: {{comdat|define|declare}}
+BAR-CMN: define weak_odr void @_Z3barv() #{{[0-9]+}} comdat
+BAR-CMN-NOT: {{define|declare}}
+BAR: declare void @_Z3foov()
+Include all the available_externally definitions required for bar (foo -> f2)
+BAR-OPT: define available_externally void @_Z3foov()
+BAR-CMN-NOT: {{define|declare}}
+BAR-OPT: declare void @_Z2f1Ri(i32*
+BAR-OPT-NOT: {{define|declare}}
+BAR-OPT: define available_externally void @_ZL2f2v()
+BAR-OPT-NOT: {{define|declare}}
+
+
+USE-OPT: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+USE-CMN-NOT: {{comdat|define|declare}}
+USE-CMN: define i32 @main()
+USE-CMN-NOT: {{define|declare}}
+USE: declare void @_Z3barv()
+Include all the available_externally definitions required for main (bar -> foo -> f2)
+USE-OPT: define available_externally void @_Z3barv()
+USE-CMN-NOT: {{define|declare}}
+USE-OPT: define available_externally void @_Z3foov()
+USE-OPT-NOT: {{define|declare}}
+USE-OPT: declare void @_Z2f1Ri(i32*
+USE-OPT-NOT: {{define|declare}}
+USE-OPT: define available_externally void @_ZL2f2v()
+USE-OPT-NOT: {{define|declare}}
diff --git a/test/Modules/codegen.test b/test/Modules/codegen.test
new file mode 100644
index 000000000000..1bdea5df4317
--- /dev/null
+++ b/test/Modules/codegen.test
@@ -0,0 +1,49 @@
+RUN: rm -rf %t
+REQUIRES: x86-registered-target
+
+RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -fmodules-debuginfo -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm
+
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - %t/foo.pcm | FileCheck --check-prefix=FOO --check-prefix=BOTH %s
+RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - -fmodules -fmodule-file=%t/foo.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=BOTH --check-prefix=USE %s
+
+For want of any better definition, inline asm goes "everywhere" the same as it
+if it were in a header (with the disadvantage that the inline asm will be
+included in the program if the module is used, even if the header containing
+the inline asm is never included - unlike a non-modular build).
+
+This is inconsistent with how namespace scope static variables are handled -
+where they only appear in the code that includes a header. This functionality
+was implemented to workaround/support the initialization of iostreams
+(implemented as a namespace scope static in the header - only to be provided
+when that specific header is included in the program).
+
+FOO: module asm "narf"
+USE: module asm "narf"
+
+FOO: $_Z2f1PKcz = comdat any
+FOO: $_ZN13implicit_dtorD1Ev = comdat any
+USE: $_Z4instIiEvv = comdat any
+FOO: $_ZN13implicit_dtorD2Ev = comdat any
+FOO: define weak_odr void @_Z2f1PKcz(i8* %fmt, ...) #{{[0-9]+}} comdat
+FOO: call void @llvm.va_start(i8* %{{[a-zA-Z0-9]*}})
+
+Test that implicit special members are emitted into the FOO module if they're
+ODR used there, otherwise emit them linkonce_odr as usual in the use.
+
+FIXME: Proactively instantiate any valid implicit special members to emit them into the module object.
+
+FOO: define weak_odr void @_ZN13implicit_dtorD1Ev
+FOO: define weak_odr void @_Z4instIfEvv
+FOO: define weak_odr void @_ZN13implicit_dtorD2Ev
+
+USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD1Ev
+USE: define linkonce_odr void @_Z4instIiEvv
+USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD2Ev
+
+Modular debug info puts the definition of a class defined in a module in that
+module's object. Users of the module only get a declaration.
+
+'distinct' is used for definition records (the flags field is empty/unspecified)
+FOO: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "implicit_dtor"
+Declarations are non-distinct and include the 'DIFlagFwdDecl' flag.
+USE: = !DICompositeType(tag: DW_TAG_structure_type, name: "implicit_dtor", {{.*}}, flags: DIFlagFwdDecl
diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp
index 59e9136bd142..401b7704900b 100644
--- a/test/Modules/cxx-templates.cpp
+++ b/test/Modules/cxx-templates.cpp
@@ -49,8 +49,14 @@ void g() {
// expected-note@Inputs/cxx-templates-a.h:11 {{candidate}}
// expected-note@Inputs/cxx-templates-b.h:11 {{candidate}}
- template_param_kinds_3<Tmpl_T_T_A>();
- template_param_kinds_3<Tmpl_T_T_B>();
+ // FIXME: This should be valid, but we incorrectly match the template template
+ // argument against both template template parameters.
+ template_param_kinds_3<Tmpl_T_T_A>(); // expected-error {{ambiguous}}
+ // expected-note@Inputs/cxx-templates-a.h:12 {{candidate}}
+ // expected-note@Inputs/cxx-templates-b.h:12 {{candidate}}
+ template_param_kinds_3<Tmpl_T_T_B>(); // expected-error {{ambiguous}}
+ // expected-note@Inputs/cxx-templates-a.h:12 {{candidate}}
+ // expected-note@Inputs/cxx-templates-b.h:12 {{candidate}}
// Trigger the instantiation of a template in 'a' that uses a type defined in
// 'common'. That type is not visible here.
diff --git a/test/Modules/cxx17.cpp b/test/Modules/cxx17.cpp
new file mode 100644
index 000000000000..1efb490828db
--- /dev/null
+++ b/test/Modules/cxx17.cpp
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x c++ -std=c++1z -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/cxx17 %s -verify -fno-modules-error-recovery
+
+// expected-no-diagnostics
+struct MergeExceptionSpec {
+ ~MergeExceptionSpec();
+} mergeExceptionSpec; // trigger evaluation of exception spec
+
+#include "decls.h"
+
+MergeExceptionSpec mergeExceptionSpec2;
diff --git a/test/Modules/dependency-dump-dependent-module.m b/test/Modules/dependency-dump-dependent-module.m
index 2430726d3ae5..490698616546 100644
--- a/test/Modules/dependency-dump-dependent-module.m
+++ b/test/Modules/dependency-dump-dependent-module.m
@@ -1,6 +1,8 @@
// When a module depends on another, check that we dump the dependency header
// files for both.
+// REQUIRES: shell
+
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -module-dependency-dir %t/vfs -F %S/Inputs -I %S/Inputs -verify %s
// expected-no-diagnostics
diff --git a/test/Modules/dependency-dump.m b/test/Modules/dependency-dump.m
index f3a487544b8e..deb66188e147 100644
--- a/test/Modules/dependency-dump.m
+++ b/test/Modules/dependency-dump.m
@@ -1,6 +1,8 @@
// Check that we can dump all of the headers a module depends on, and a VFS map
// for the same.
+// REQUIRES: shell
+
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -module-dependency-dir %t/vfs -F %S/Inputs -I %S/Inputs -verify %s
// expected-no-diagnostics
diff --git a/test/Modules/diag-pragma.cpp b/test/Modules/diag-pragma.cpp
new file mode 100644
index 000000000000..347401fffc20
--- /dev/null
+++ b/test/Modules/diag-pragma.cpp
@@ -0,0 +1,47 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -emit-module -fmodules-cache-path=%t -fmodule-name=diag_pragma -x c++ %S/Inputs/module.map -fmodules-ts
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_pragma -x c++ %S/Inputs/module.map -fmodules-ts -o %t/explicit.pcm -Werror=string-plus-int
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DEXPLICIT_FLAG -fmodule-file=%t/explicit.pcm
+
+import diag_pragma;
+
+int foo(int x) {
+ // Diagnostics from templates in the module follow the diagnostic state from
+ // when the module was built.
+#ifdef EXPLICIT_FLAG
+ // expected-error@diag_pragma.h:7 {{adding 'int' to a string}}
+#else
+ // expected-warning@diag_pragma.h:7 {{adding 'int' to a string}}
+#endif
+ // expected-note@diag_pragma.h:7 {{use array indexing}}
+ f(0); // expected-note {{instantiation of}}
+
+ g(0); // ok, warning was ignored when building module
+
+ // Diagnostics from this source file ignore the diagnostic state from the
+ // module.
+ void("foo" + x); // expected-warning {{adding 'int' to a string}}
+ // expected-note@-1 {{use array indexing}}
+
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+
+ // Diagnostics from the module ignore diagnostic state changes from this
+ // source file.
+#ifdef EXPLICIT_FLAG
+ // expected-error@diag_pragma.h:7 {{adding 'long' to a string}}
+#else
+ // expected-warning@diag_pragma.h:7 {{adding 'long' to a string}}
+#endif
+ // expected-note@diag_pragma.h:7 {{use array indexing}}
+ f(0L); // expected-note {{instantiation of}}
+
+ g(0L);
+
+ void("bar" + x);
+
+ if (x = DIAG_PRAGMA_MACRO) // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note {{place parentheses}} expected-note {{use '=='}}
+ return 0;
+ return 1;
+}
diff --git a/test/Modules/diagnostic-options-out-of-date.m b/test/Modules/diagnostic-options-out-of-date.m
index ed9e8e1fe183..fd98a8f99d66 100644
--- a/test/Modules/diagnostic-options-out-of-date.m
+++ b/test/Modules/diagnostic-options-out-of-date.m
@@ -7,6 +7,16 @@
// RUN: %clang_cc1 -Werror -Wconversion -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs %s -fmodules-disable-diagnostic-validation
// Make sure we don't error out when using the pch
// RUN: %clang_cc1 -Werror -Wno-conversion -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fsyntax-only -I %S/Inputs -include-pch %t.pch %s -verify -fmodules-disable-diagnostic-validation
+
+// Build A.pcm
+// RUN: %clang_cc1 -Werror -Wno-conversion -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs %s
+// Build pch that imports A.pcm
+// RUN: %clang_cc1 -Werror -Wno-conversion -emit-pch -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -o %t.pch -I %S/Inputs -x objective-c-header %S/Inputs/pch-import-module-out-of-date.pch
+// We will rebuild A.pcm and overwrite the original A.pcm that the pch imports, but the two versions have the same hash.
+// RUN: %clang_cc1 -Werror -Wconversion -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs %s
+// Make sure we don't error out when using the pch
+// RUN: %clang_cc1 -Werror -Wno-conversion -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fsyntax-only -I %S/Inputs -include-pch %t.pch %s -verify
+
// expected-no-diagnostics
@import DiagOutOfDate;
diff --git a/test/Modules/find-privateheaders.m b/test/Modules/find-privateheaders.m
new file mode 100644
index 000000000000..c5e82ac70da2
--- /dev/null
+++ b/test/Modules/find-privateheaders.m
@@ -0,0 +1,2 @@
+// RUN: %clang_cc1 -fmodules -fsyntax-only -F%S/Inputs %s
+#import "Main/Main.h"
diff --git a/test/Modules/gnumode-non-benign.cpp b/test/Modules/gnumode-non-benign.cpp
new file mode 100644
index 000000000000..9255dfe24b11
--- /dev/null
+++ b/test/Modules/gnumode-non-benign.cpp
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I%S/Inputs/gnumode-non-benign -verify %s
+
+// expected-no-diagnostics
+
+// This test ensures that submodules have the same GNUMode language option
+// setting as the main clang invocation.
+// Note that we set GNUMode = 0 with -std=c++11 for this file.
+
+// This module fails to compile with GNUMode = 1.
+#include "module.h"
diff --git a/test/Modules/hidden-names.cpp b/test/Modules/hidden-names.cpp
new file mode 100644
index 000000000000..ba945a1d3c8b
--- /dev/null
+++ b/test/Modules/hidden-names.cpp
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/hidden-names %s -verify
+// expected-no-diagnostics
+
+#include "visible.h"
+
+using namespace NS;
+
+namespace {
+ struct X { void f(); };
+}
+
+void X::f() {}
diff --git a/test/Modules/implicit-built-Werror-using-W.cpp b/test/Modules/implicit-built-Werror-using-W.cpp
new file mode 100644
index 000000000000..9fb7a6bf0b03
--- /dev/null
+++ b/test/Modules/implicit-built-Werror-using-W.cpp
@@ -0,0 +1,42 @@
+// Check that implicit modules builds give correct diagnostics, even when
+// reusing a module built with strong -Werror flags.
+//
+// Clear the caches.
+// RUN: rm -rf %t.cache %t-pragma.cache
+//
+// Build with -Werror, then with -W, and then with neither.
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
+// RUN: -Werror=shorten-64-to-32 \
+// RUN: -I%S/Inputs/implicit-built-Werror-using-W -fimplicit-module-maps \
+// RUN: -fmodules-cache-path=%t.cache -x c++ %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-ERROR
+// RUN: %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
+// RUN: -Wshorten-64-to-32 \
+// RUN: -I%S/Inputs/implicit-built-Werror-using-W -fimplicit-module-maps \
+// RUN: -fdisable-module-hash \
+// RUN: -fmodules-cache-path=%t.cache -x c++ %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-WARN
+// RUN: %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
+// RUN: -I%S/Inputs/implicit-built-Werror-using-W -fimplicit-module-maps \
+// RUN: -fmodules-cache-path=%t.cache -x c++ %s 2>&1 \
+// RUN: | FileCheck %s -allow-empty
+//
+// In the presence of a warning pragma, build with -Werror and then without.
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
+// RUN: -DUSE_PRAGMA -Werror=shorten-64-to-32 \
+// RUN: -I%S/Inputs/implicit-built-Werror-using-W -fimplicit-module-maps \
+// RUN: -fmodules-cache-path=%t-pragma.cache -x c++ %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-ERROR
+// RUN: %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
+// RUN: -DUSE_PRAGMA \
+// RUN: -I%S/Inputs/implicit-built-Werror-using-W -fimplicit-module-maps \
+// RUN: -fmodules-cache-path=%t-pragma.cache -x c++ %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-WARN
+#include <convert.h>
+
+long long foo() { return convert<long long>(0); }
+
+// CHECK-ERROR: error: implicit conversion
+// CHECK-WARN: warning: implicit conversion
+// CHECK-NOT: error: implicit conversion
+// CHECK-NOT: warning: implicit conversion
diff --git a/test/Modules/implicit-private-with-different-name.m b/test/Modules/implicit-private-with-different-name.m
index 3d8f937973f0..c09d3979c3e1 100644
--- a/test/Modules/implicit-private-with-different-name.m
+++ b/test/Modules/implicit-private-with-different-name.m
@@ -3,7 +3,7 @@
// Build PCH using A, with adjacent private module APrivate, which winds up being implicitly referenced
// RUN: %clang_cc1 -verify -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -F %S/Inputs/implicit-private-with-different-name -emit-pch -o %t-A.pch %s
-// Use the PCH with no explicit way to resolve PrivateA, still pick it up through MODULE_DIRECTORY reference in PCH control block
+// Use the PCH with no explicit way to resolve APrivate, still pick it up by automatic second-chance search for "A" with "Private" appended
// RUN: %clang_cc1 -verify -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -F %S/Inputs/implicit-private-with-different-name -include-pch %t-A.pch %s -fsyntax-only
// Check the fixit
diff --git a/test/Modules/invalid-pch-module-id.m b/test/Modules/invalid-pch-module-id.m
new file mode 100644
index 000000000000..34d9995cef6d
--- /dev/null
+++ b/test/Modules/invalid-pch-module-id.m
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t.cache
+//
+// RUN: %clang_cc1 -x objective-c-header -fmodules -F%S/Inputs/invalid-module-id \
+// RUN: -fmodule-implementation-of NC -fmodules-cache-path=%t.cache \
+// RUN: -fimplicit-module-maps \
+// RUN: -emit-pch %S/Inputs/invalid-module-id/NC-Prefix.pch -o %t.pch
+//
+// RUN: %clang_cc1 -x objective-c -fmodules -F%S/Inputs/invalid-module-id \
+// RUN: -fmodule-implementation-of NC -fmodules-cache-path=%t.cache \
+// RUN: -fimplicit-module-maps -include-pch %t.pch %s -fsyntax-only
+
+#import <NC/NULog.h>
+#import <NC/NUGeometry.h>
diff --git a/test/Modules/localsubmodulevis.m b/test/Modules/localsubmodulevis.m
new file mode 100644
index 000000000000..f8c4b3c755eb
--- /dev/null
+++ b/test/Modules/localsubmodulevis.m
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fimplicit-module-maps -fmodules-cache-path=%t.a -I %S/Inputs/preprocess -verify %s
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fimplicit-module-maps -fmodules-cache-path=%t.b -I %S/Inputs/preprocess -x c -verify -x c %s
+
+// expected-no-diagnostics
+
+#include "file.h"
+
diff --git a/test/Modules/merge-function-defs.cpp b/test/Modules/merge-function-defs.cpp
new file mode 100644
index 000000000000..2f08f523c3aa
--- /dev/null
+++ b/test/Modules/merge-function-defs.cpp
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I%S/Inputs/merge-function-defs -fmodules -fmodule-map-file=%S/Inputs/merge-function-defs/map -fmodules-cache-path=%t %s -emit-llvm-only
+
+#include "b.h"
+
+struct X {
+ virtual void f();
+};
+inline void X::f() {}
+
+X x;
diff --git a/test/Modules/merge-name-for-linkage.cpp b/test/Modules/merge-name-for-linkage.cpp
index 75534bd661b9..1fd16865ca7b 100644
--- a/test/Modules/merge-name-for-linkage.cpp
+++ b/test/Modules/merge-name-for-linkage.cpp
@@ -7,3 +7,4 @@ typedef pthread_mutex_t pthread_mutex_t;
pthread_mutex_t x;
#include "b.h"
pthread_mutex_t y;
+merged_after_definition z;
diff --git a/test/Modules/merge-using-decls.cpp b/test/Modules/merge-using-decls.cpp
index 98989d12f985..1ec9a9a17bde 100644
--- a/test/Modules/merge-using-decls.cpp
+++ b/test/Modules/merge-using-decls.cpp
@@ -1,6 +1,10 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=1
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++98 %s -DORDER=1
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++11 %s -DORDER=1
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=2
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++98 %s -DORDER=2
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify -std=c++11 %s -DORDER=2
#if ORDER == 1
#include "a.h"
@@ -24,7 +28,11 @@ template<typename T> int Use() {
}
template<typename T> int UseAll() {
+#if __cplusplus <= 199711L // C++11 does not allow access declarations
return Use<C<T> >() + Use<D<T> >() + Use<E<T> >() + Use<F<T> >(); // expected-note 0-2{{instantiation of}}
+#else
+ return Use<C<T> >() + Use<D<T> >() + Use<F<T> >(); // expected-note 0-2{{instantiation of}}
+#endif
}
template int UseAll<YA>();
@@ -37,8 +45,10 @@ template int UseAll<Y>();
// Here, we're instantiating the definition from 'A' and merging the definition
// from 'B' into it.
+#if __cplusplus <= 199711L // C++11 does not allow access declarations
// expected-error@b.h:* {{'E::value' from module 'B' is not present in definition of 'E<T>' in module 'A'}}
// expected-error@b.h:* {{'E::v' from module 'B' is not present in definition of 'E<T>' in module 'A'}}
+#endif
// expected-error@b.h:* {{'F::type' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
// expected-error@b.h:* {{'F::t' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
@@ -55,11 +65,14 @@ template int UseAll<Y>();
// expected-error@b.h:* 2{{'typename' keyword used on a non-type}}
// expected-error@b.h:* 2{{dependent using declaration resolved to type without 'typename'}}
+#if __cplusplus <= 199711L // C++11 does not allow access declarations
// expected-error@a.h:* {{'E::type' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
// expected-error@a.h:* {{'E::t' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
// expected-error@a.h:* {{'E::value' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
// expected-error@a.h:* {{'E::v' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
// expected-note@b.h:* 2{{definition has no member}}
+#endif
+
// expected-error@a.h:* {{'F::type' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
// expected-error@a.h:* {{'F::t' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
diff --git a/test/Modules/module-impl-with-link.c b/test/Modules/module-impl-with-link.c
index 5e5ca83aafd6..3bd4c4abd92b 100644
--- a/test/Modules/module-impl-with-link.c
+++ b/test/Modules/module-impl-with-link.c
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fmodule-name=Clib %s -I %S/Inputs/module-impl-with-link -emit-llvm -o -
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fmodule-name=Clib %s -I %S/Inputs/module-impl-with-link -emit-llvm -o - | FileCheck %s
#include "foo.h"
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[LINK_OPTIONS:[0-9]+]]}
// Make sure we don't generate linker option for module Clib since this TU is
diff --git a/test/Modules/module_file_info.m b/test/Modules/module_file_info.m
index fa841b75926c..f2967be6f8ca 100644
--- a/test/Modules/module_file_info.m
+++ b/test/Modules/module_file_info.m
@@ -29,13 +29,9 @@
// CHECK: CPU:
// CHECK: ABI:
-// CHECK: Diagnostic options:
-// CHECK: IgnoreWarnings: Yes
-// CHECK: Diagnostic flags:
-// CHECK: -Wunused
-
// CHECK: Header search options:
// CHECK: System root [-isysroot=]: '/'
+// CHECK: Resource dir [ -resource-dir=]: '{{.*}}clang{{.*}}'
// CHECK: Use builtin include directories [-nobuiltininc]: Yes
// CHECK: Use standard system include directories [-nostdinc]: No
// CHECK: Use standard C++ include directories [-nostdinc++]: Yes
@@ -47,3 +43,8 @@
// CHECK: Predefined macros:
// CHECK: -DBLARG
// CHECK: -DWIBBLE=WOBBLE
+
+// CHECK: Diagnostic options:
+// CHECK: IgnoreWarnings: Yes
+// CHECK: Diagnostic flags:
+// CHECK: -Wunused
diff --git a/test/Modules/module_map_cwd.c b/test/Modules/module_map_cwd.c
new file mode 100644
index 000000000000..d76734adeeb5
--- /dev/null
+++ b/test/Modules/module_map_cwd.c
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'module X { header "x.h" }' > %t/map
+// RUN: echo 'extern int n;' > %t/x.h
+// RUN: cd %t
+// RUN: %clang_cc1 %s -fmodules -fmodule-map-file=map -fmodules-cache-path=. -verify -I.
+// expected-no-diagnostics
+#include "x.h"
+int *m = &n;
diff --git a/test/Modules/modules-cache-path-canonicalization.m b/test/Modules/modules-cache-path-canonicalization.m
new file mode 100644
index 000000000000..9d68cb06faf8
--- /dev/null
+++ b/test/Modules/modules-cache-path-canonicalization.m
@@ -0,0 +1,30 @@
+// RUN: rm -rf %t/cache %T/rel
+
+// This testcase reproduces a use-after-free after looking up a PCM in
+// a non-canonical modules-cache-path.
+//
+// Prime the module cache (note the '.' in the path).
+// RUN: %clang_cc1 -fdisable-module-hash -fmodules-cache-path=%t/./cache \
+// RUN: -fmodules -fimplicit-module-maps -I %S/Inputs/outofdate-rebuild \
+// RUN: %s -fsyntax-only
+//
+// Force a module to be rebuilt by creating a conflict.
+// RUN: echo "@import CoreText;" > %t.m
+// RUN: %clang_cc1 -DMISMATCH -Werror -fdisable-module-hash \
+// RUN: -fmodules-cache-path=%t/./cache -fmodules -fimplicit-module-maps \
+// RUN: -I %S/Inputs/outofdate-rebuild %t.m -fsyntax-only
+//
+// Rebuild.
+// RUN: %clang_cc1 -fdisable-module-hash -fmodules-cache-path=%t/./cache \
+// RUN: -fmodules -fimplicit-module-maps -I %S/Inputs/outofdate-rebuild \
+// RUN: %s -fsyntax-only
+
+
+// Unrelated to the above: Check that a relative path is resolved correctly.
+//
+// RUN: %clang_cc1 -working-directory %T/rel -fmodules-cache-path=./cache \
+// RUN: -fmodules -fimplicit-module-maps -I %S/Inputs/outofdate-rebuild \
+// RUN: -fdisable-module-hash %t.m -fsyntax-only -Rmodule-build 2>&1 \
+// RUN: | FileCheck %s
+// CHECK: {{/|\\}}rel{{/|\\}}cache{{/|\\}}CoreText.pcm
+@import Cocoa;
diff --git a/test/Modules/objc-categories.m b/test/Modules/objc-categories.m
index 42baf352fbf5..fcffe3cc9620 100644
--- a/test/Modules/objc-categories.m
+++ b/test/Modules/objc-categories.m
@@ -53,6 +53,9 @@ void test_hidden_all_errors(Foo *foo) {
p3p = foo.p3_prop; // expected-error{{property 'p3_prop' not found on object of type 'Foo *'}}
id p4p = p4.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'id<P4>'}}
p4p = foo.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'Foo *'}}
+
+ if (foo.hiddenPropertyFromExtension) { // expected-error {{property 'hiddenPropertyFromExtension' not found on object of type 'Foo *'}}
+ }
}
@import category_left.sub;
@@ -74,6 +77,7 @@ void test_hidden_right_errors(Foo *foo) {
id p4p = p4.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'id<P4>'}}
p4p = foo.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'Foo *'; did you mean 'p3_prop'?}}
// expected-note@Inputs/category_left_sub.h:7{{'p3_prop' declared here}}
+ int hiddenFromExtension = foo.hiddenPropertyFromExtension; // expected-error {{property 'hiddenPropertyFromExtension' not found on object of type 'Foo *'}}
}
@import category_right.sub;
@@ -92,4 +96,6 @@ void test_hidden_okay(Foo *foo) {
p3p = foo.p3_prop;
id p4p = p4.p4_prop;
p4p = foo.p4_prop;
+ if (foo.hiddenPropertyFromExtension) {
+ }
}
diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp
new file mode 100644
index 000000000000..75436706200c
--- /dev/null
+++ b/test/Modules/odr_hash.cpp
@@ -0,0 +1,953 @@
+// Clear and create directories
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: mkdir %t/cache
+// RUN: mkdir %t/Inputs
+
+// Build first header file
+// RUN: echo "#define FIRST" >> %t/Inputs/first.h
+// RUN: cat %s >> %t/Inputs/first.h
+
+// Build second header file
+// RUN: echo "#define SECOND" >> %t/Inputs/second.h
+// RUN: cat %s >> %t/Inputs/second.h
+
+// Build module map file
+// RUN: echo "module FirstModule {" >> %t/Inputs/module.map
+// RUN: echo " header \"first.h\"" >> %t/Inputs/module.map
+// RUN: echo "}" >> %t/Inputs/module.map
+// RUN: echo "module SecondModule {" >> %t/Inputs/module.map
+// RUN: echo " header \"second.h\"" >> %t/Inputs/module.map
+// RUN: echo "}" >> %t/Inputs/module.map
+
+// Run test
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -std=c++1z
+
+#if !defined(FIRST) && !defined(SECOND)
+#include "first.h"
+#include "second.h"
+#endif
+
+namespace AccessSpecifiers {
+#if defined(FIRST)
+struct S1 {
+};
+#elif defined(SECOND)
+struct S1 {
+ private:
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'AccessSpecifiers::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found end of class}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ public:
+};
+#elif defined(SECOND)
+struct S2 {
+ protected:
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'AccessSpecifiers::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found protected access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace AccessSpecifiers
+
+namespace StaticAssert {
+#if defined(FIRST)
+struct S1 {
+ static_assert(1 == 1, "First");
+};
+#elif defined(SECOND)
+struct S1 {
+ static_assert(1 == 1, "Second");
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'StaticAssert::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with message}}
+// expected-note@first.h:* {{but in 'FirstModule' found static assert with different message}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ static_assert(2 == 2, "Message");
+};
+#elif defined(SECOND)
+struct S2 {
+ static_assert(2 == 2);
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'StaticAssert::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with no message}}
+// expected-note@first.h:* {{but in 'FirstModule' found static assert with message}}
+#endif
+
+#if defined(FIRST)
+struct S3 {
+ static_assert(3 == 3, "Message");
+};
+#elif defined(SECOND)
+struct S3 {
+ static_assert(3 != 4, "Message");
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'StaticAssert::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with condition}}
+// expected-note@first.h:* {{but in 'FirstModule' found static assert with different condition}}
+#endif
+
+#if defined(FIRST)
+struct S4 {
+ static_assert(4 == 4, "Message");
+};
+#elif defined(SECOND)
+struct S4 {
+ public:
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'StaticAssert::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found static assert}}
+#endif
+}
+
+namespace Field {
+#if defined(FIRST)
+struct S1 {
+ int x;
+ private:
+ int y;
+};
+#elif defined(SECOND)
+struct S1 {
+ int x;
+ int y;
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'Field::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ int x;
+ int y;
+};
+#elif defined(SECOND)
+struct S2 {
+ int y;
+ int x;
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'Field::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'y'}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S3 {
+ double x;
+};
+#elif defined(SECOND)
+struct S3 {
+ int x;
+};
+#else
+S3 s3;
+// expected-error@first.h:* {{'Field::S3::x' from module 'FirstModule' is not present in definition of 'Field::S3' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+typedef int A;
+struct S4 {
+ A x;
+};
+
+struct S5 {
+ A x;
+};
+#elif defined(SECOND)
+typedef int B;
+struct S4 {
+ B x;
+};
+
+struct S5 {
+ int x;
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'Field::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'Field::B' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'Field::A' (aka 'int')}}
+
+S5 s5;
+// expected-error@second.h:* {{'Field::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'int'}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'Field::A' (aka 'int')}}
+#endif
+
+#if defined(FIRST)
+struct S6 {
+ unsigned x;
+};
+#elif defined(SECOND)
+struct S6 {
+ unsigned x : 1;
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'Field::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x'}}
+// expected-note@first.h:* {{but in 'FirstModule' found non-bitfield 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S7 {
+ unsigned x : 2;
+};
+#elif defined(SECOND)
+struct S7 {
+ unsigned x : 1;
+};
+#else
+S7 s7;
+// expected-error@second.h:* {{'Field::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x' with one width expression}}
+// expected-note@first.h:* {{but in 'FirstModule' found bitfield 'x' with different width expression}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+ unsigned x : 2;
+};
+#elif defined(SECOND)
+struct S8 {
+ unsigned x : 1 + 1;
+};
+#else
+S8 s8;
+// expected-error@second.h:* {{'Field::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x' with one width expression}}
+// expected-note@first.h:* {{but in 'FirstModule' found bitfield 'x' with different width expression}}
+#endif
+
+#if defined(FIRST)
+struct S9 {
+ mutable int x;
+};
+#elif defined(SECOND)
+struct S9 {
+ int x;
+};
+#else
+S9 s9;
+// expected-error@second.h:* {{'Field::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found non-mutable field 'x'}}
+// expected-note@first.h:* {{but in 'FirstModule' found mutable field 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S10 {
+ unsigned x = 5;
+};
+#elif defined(SECOND)
+struct S10 {
+ unsigned x;
+};
+#else
+S10 s10;
+// expected-error@second.h:* {{'Field::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with no initalizer}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with an initializer}}
+#endif
+
+#if defined(FIRST)
+struct S11 {
+ unsigned x = 5;
+};
+#elif defined(SECOND)
+struct S11 {
+ unsigned x = 7;
+};
+#else
+S11 s11;
+// expected-error@second.h:* {{'Field::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with a different initializer}}
+#endif
+
+} // namespace Field
+
+namespace Method {
+#if defined(FIRST)
+struct S1 {
+ void A() {}
+};
+#elif defined(SECOND)
+struct S1 {
+ private:
+ void A() {}
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'Method::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found method}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ void A() {}
+ void B() {}
+};
+#elif defined(SECOND)
+struct S2 {
+ void B() {}
+ void A() {}
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'Method::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'B'}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A'}}
+#endif
+
+#if defined(FIRST)
+struct S3 {
+ static void A() {}
+ void A(int) {}
+};
+#elif defined(SECOND)
+struct S3 {
+ void A(int) {}
+ static void A() {}
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'Method::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not static}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is static}}
+#endif
+
+#if defined(FIRST)
+struct S4 {
+ virtual void A() {}
+ void B() {}
+};
+#elif defined(SECOND)
+struct S4 {
+ void A() {}
+ virtual void B() {}
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'Method::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not virtual}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is virtual}}
+#endif
+
+#if defined(FIRST)
+struct S5 {
+ virtual void A() = 0;
+ virtual void B() {};
+};
+#elif defined(SECOND)
+struct S5 {
+ virtual void A() {}
+ virtual void B() = 0;
+};
+#else
+S5 *s5;
+// expected-error@second.h:* {{'Method::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is virtual}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is pure virtual}}
+#endif
+
+#if defined(FIRST)
+struct S6 {
+ inline void A() {}
+};
+#elif defined(SECOND)
+struct S6 {
+ void A() {}
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'Method::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not inline}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is inline}}
+#endif
+
+#if defined(FIRST)
+struct S7 {
+ void A() volatile {}
+ void A() {}
+};
+#elif defined(SECOND)
+struct S7 {
+ void A() {}
+ void A() volatile {}
+};
+#else
+S7 s7;
+// expected-error@second.h:* {{'Method::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not volatile}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is volatile}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+ void A() const {}
+ void A() {}
+};
+#elif defined(SECOND)
+struct S8 {
+ void A() {}
+ void A() const {}
+};
+#else
+S8 s8;
+// expected-error@second.h:* {{'Method::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not const}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is const}}
+#endif
+
+} // namespace Method
+
+// Naive parsing of AST can lead to cycles in processing. Ensure
+// self-references don't trigger an endless cycles of AST node processing.
+namespace SelfReference {
+#if defined(FIRST)
+template <template <int> class T> class Wrapper {};
+
+template <int N> class S {
+ S(Wrapper<::SelfReference::S> &Ref) {}
+};
+
+struct Xx {
+ struct Yy {
+ };
+};
+
+Xx::Xx::Xx::Yy yy;
+
+namespace NNS {
+template <typename> struct Foo;
+template <template <class> class T = NNS::Foo>
+struct NestedNamespaceSpecifier {};
+}
+#endif
+} // namespace SelfReference
+
+namespace TypeDef {
+#if defined(FIRST)
+struct S1 {
+ typedef int a;
+};
+#elif defined(SECOND)
+struct S1 {
+ typedef double a;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'TypeDef::S1::a' from module 'FirstModule' is not present in definition of 'TypeDef::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'a' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ typedef int a;
+};
+#elif defined(SECOND)
+struct S2 {
+ typedef int b;
+};
+#else
+S2 s2;
+// expected-error@first.h:* {{'TypeDef::S2::a' from module 'FirstModule' is not present in definition of 'TypeDef::S2' in module 'SecondModule'}}
+// expected-note@second.h:* {{definition has no member 'a'}}
+#endif
+
+#if defined(FIRST)
+typedef int T;
+struct S3 {
+ typedef T a;
+};
+#elif defined(SECOND)
+typedef double T;
+struct S3 {
+ typedef T a;
+};
+#else
+S3 s3;
+// expected-error@first.h:* {{'TypeDef::S3::a' from module 'FirstModule' is not present in definition of 'TypeDef::S3' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'a' does not match}}
+#endif
+} // namespace TypeDef
+
+namespace Using {
+#if defined(FIRST)
+struct S1 {
+ using a = int;
+};
+#elif defined(SECOND)
+struct S1 {
+ using a = double;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'Using::S1::a' from module 'FirstModule' is not present in definition of 'Using::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'a' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ using a = int;
+};
+#elif defined(SECOND)
+struct S2 {
+ using b = int;
+};
+#else
+S2 s2;
+// expected-error@first.h:* {{'Using::S2::a' from module 'FirstModule' is not present in definition of 'Using::S2' in module 'SecondModule'}}
+// expected-note@second.h:* {{definition has no member 'a'}}
+#endif
+
+#if defined(FIRST)
+typedef int T;
+struct S3 {
+ using a = T;
+};
+#elif defined(SECOND)
+typedef double T;
+struct S3 {
+ using a = T;
+};
+#else
+S3 s3;
+// expected-error@first.h:* {{'Using::S3::a' from module 'FirstModule' is not present in definition of 'Using::S3' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'a' does not match}}
+#endif
+} // namespace Using
+
+
+// Interesting cases that should not cause errors. struct S should not error
+// while struct T should error at the access specifier mismatch at the end.
+namespace AllDecls {
+#if defined(FIRST)
+typedef int INT;
+struct S {
+ public:
+ private:
+ protected:
+
+ static_assert(1 == 1, "Message");
+ static_assert(2 == 2);
+
+ int x;
+ double y;
+
+ INT z;
+
+ unsigned a : 1;
+ unsigned b : 2*2 + 5/2;
+
+ mutable int c = sizeof(x + y);
+
+ void method() {}
+ static void static_method() {}
+ virtual void virtual_method() {}
+ virtual void pure_virtual_method() = 0;
+ inline void inline_method() {}
+ void volatile_method() volatile {}
+ void const_method() const {}
+
+ typedef int typedef_int;
+ using using_int = int;
+};
+#elif defined(SECOND)
+typedef int INT;
+struct S {
+ public:
+ private:
+ protected:
+
+ static_assert(1 == 1, "Message");
+ static_assert(2 == 2);
+
+ int x;
+ double y;
+
+ INT z;
+
+ unsigned a : 1;
+ unsigned b : 2 * 2 + 5 / 2;
+
+ mutable int c = sizeof(x + y);
+
+ void method() {}
+ static void static_method() {}
+ virtual void virtual_method() {}
+ virtual void pure_virtual_method() = 0;
+ inline void inline_method() {}
+ void volatile_method() volatile {}
+ void const_method() const {}
+
+ typedef int typedef_int;
+ using using_int = int;
+};
+#else
+S *s;
+#endif
+
+#if defined(FIRST)
+typedef int INT;
+struct T {
+ public:
+ private:
+ protected:
+
+ static_assert(1 == 1, "Message");
+ static_assert(2 == 2);
+
+ int x;
+ double y;
+
+ INT z;
+
+ unsigned a : 1;
+ unsigned b : 2 * 2 + 5 / 2;
+
+ mutable int c = sizeof(x + y);
+
+ void method() {}
+ static void static_method() {}
+ virtual void virtual_method() {}
+ virtual void pure_virtual_method() = 0;
+ inline void inline_method() {}
+ void volatile_method() volatile {}
+ void const_method() const {}
+
+ typedef int typedef_int;
+ using using_int = int;
+
+ private:
+};
+#elif defined(SECOND)
+typedef int INT;
+struct T {
+ public:
+ private:
+ protected:
+
+ static_assert(1 == 1, "Message");
+ static_assert(2 == 2);
+
+ int x;
+ double y;
+
+ INT z;
+
+ unsigned a : 1;
+ unsigned b : 2 * 2 + 5 / 2;
+
+ mutable int c = sizeof(x + y);
+
+ void method() {}
+ static void static_method() {}
+ virtual void virtual_method() {}
+ virtual void pure_virtual_method() = 0;
+ inline void inline_method() {}
+ void volatile_method() volatile {}
+ void const_method() const {}
+
+ typedef int typedef_int;
+ using using_int = int;
+
+ public:
+};
+#else
+T *t;
+// expected-error@second.h:* {{'AllDecls::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+}
+
+namespace FriendFunction {
+#if defined(FIRST)
+void F(int = 0);
+struct S { friend void F(int); };
+#elif defined(SECOND)
+void F(int);
+struct S { friend void F(int); };
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+void G(int = 0);
+struct T {
+ friend void G(int);
+
+ private:
+};
+#elif defined(SECOND)
+void G(int);
+struct T {
+ friend void G(int);
+
+ public:
+};
+#else
+T t;
+// expected-error@second.h:* {{'FriendFunction::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+} // namespace FriendFunction
+
+namespace ImplicitDecl {
+#if defined(FIRST)
+struct S { };
+void S_Constructors() {
+ // Trigger creation of implicit contructors
+ S foo;
+ S bar = foo;
+ S baz(bar);
+}
+#elif defined(SECOND)
+struct S { };
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+struct T {
+ private:
+};
+void T_Constructors() {
+ // Trigger creation of implicit contructors
+ T foo;
+ T bar = foo;
+ T baz(bar);
+}
+#elif defined(SECOND)
+struct T {
+ public:
+};
+#else
+T t;
+// expected-error@first.h:* {{'ImplicitDecl::T' has different definitions in different modules; first difference is definition in module 'FirstModule' found private access specifier}}
+// expected-note@second.h:* {{but in 'SecondModule' found public access specifier}}
+#endif
+
+} // namespace ImplicitDelc
+
+namespace TemplatedClass {
+#if defined(FIRST)
+template <class>
+struct S {};
+#elif defined(SECOND)
+template <class>
+struct S {};
+#else
+S<int> s;
+#endif
+
+#if defined(FIRST)
+template <class>
+struct T {
+ private:
+};
+#elif defined(SECOND)
+template <class>
+struct T {
+ public:
+};
+#else
+T<int> t;
+// expected-error@second.h:* {{'TemplatedClass::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+} // namespace TemplatedClass
+
+namespace TemplateClassWithField {
+#if defined(FIRST)
+template <class A>
+struct S {
+ A a;
+};
+#elif defined(SECOND)
+template <class A>
+struct S {
+ A a;
+};
+#else
+S<int> s;
+#endif
+
+#if defined(FIRST)
+template <class A>
+struct T {
+ A a;
+
+ private:
+};
+#elif defined(SECOND)
+template <class A>
+struct T {
+ A a;
+
+ public:
+};
+#else
+T<int> t;
+// expected-error@second.h:* {{'TemplateClassWithField::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+} // namespace TemplateClassWithField
+
+namespace TemplateClassWithTemplateField {
+#if defined(FIRST)
+template <class A>
+class WrapperS;
+template <class A>
+struct S {
+ WrapperS<A> a;
+};
+#elif defined(SECOND)
+template <class A>
+class WrapperS;
+template <class A>
+struct S {
+ WrapperS<A> a;
+};
+#else
+template <class A>
+class WrapperS{};
+S<int> s;
+#endif
+
+#if defined(FIRST)
+template <class A>
+class WrapperT;
+template <class A>
+struct T {
+ WrapperT<A> a;
+
+ public:
+};
+#elif defined(SECOND)
+template <class A>
+class WrapperT;
+template <class A>
+struct T {
+ WrapperT<A> a;
+
+ private:
+};
+#else
+template <class A>
+class WrapperT{};
+T<int> t;
+// expected-error@second.h:* {{'TemplateClassWithTemplateField::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace TemplateClassWithTemplateField
+
+namespace EnumWithForwardDeclaration {
+#if defined(FIRST)
+enum E : int;
+struct S {
+ void get(E) {}
+};
+#elif defined(SECOND)
+enum E : int { A, B };
+struct S {
+ void get(E) {}
+};
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+struct T {
+ void get(E) {}
+ public:
+};
+#elif defined(SECOND)
+struct T {
+ void get(E) {}
+ private:
+};
+#else
+T t;
+// expected-error@second.h:* {{'EnumWithForwardDeclaration::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace EnumWithForwardDeclaration
+
+namespace StructWithForwardDeclaration {
+#if defined(FIRST)
+struct P {};
+struct S {
+ struct P *ptr;
+};
+#elif defined(SECOND)
+struct S {
+ struct P *ptr;
+};
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+struct Q {};
+struct T {
+ struct Q *ptr;
+ public:
+};
+#elif defined(SECOND)
+struct T {
+ struct Q *ptr;
+ private:
+};
+#else
+T t;
+// expected-error@second.h:* {{'StructWithForwardDeclaration::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace StructWithForwardDeclaration
+
+namespace StructWithForwardDeclarationNoDefinition {
+#if defined(FIRST)
+struct P;
+struct S {
+ struct P *ptr;
+};
+#elif defined(SECOND)
+struct S {
+ struct P *ptr;
+};
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+struct Q;
+struct T {
+ struct Q *ptr;
+
+ public:
+};
+#elif defined(SECOND)
+struct T {
+ struct Q *ptr;
+
+ private:
+};
+#else
+T t;
+// expected-error@second.h:* {{'StructWithForwardDeclarationNoDefinition::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace StructWithForwardDeclarationNoDefinition
+
+// Keep macros contained to one file.
+#ifdef FIRST
+#undef FIRST
+#endif
+#ifdef SECOND
+#undef SECOND
+#endif
diff --git a/test/Modules/outofdate-rebuild.m b/test/Modules/outofdate-rebuild.m
new file mode 100644
index 000000000000..510325f62dcb
--- /dev/null
+++ b/test/Modules/outofdate-rebuild.m
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t.cache
+// RUN: echo "@import CoreText;" > %t.m
+// RUN: %clang_cc1 -fdisable-module-hash -fmodules-cache-path=%t.cache \
+// RUN: -fmodules -fimplicit-module-maps -I%S/Inputs/outofdate-rebuild %s \
+// RUN: -fsyntax-only
+// RUN: %clang_cc1 -DMISMATCH -Werror -fdisable-module-hash \
+// RUN: -fmodules-cache-path=%t.cache -fmodules -fimplicit-module-maps \
+// RUN: -I%S/Inputs/outofdate-rebuild %t.m -fsyntax-only
+// RUN: %clang_cc1 -fdisable-module-hash -fmodules-cache-path=%t.cache \
+// RUN: -fmodules -fimplicit-module-maps -I%S/Inputs/outofdate-rebuild %s \
+// RUN: -fsyntax-only
+
+// This testcase reproduces a use-after-free in when ModuleManager removes an
+// entry from the PCMCache without notifying its parent ASTReader.
+@import Cocoa;
diff --git a/test/Modules/overloadable-attrs.cpp b/test/Modules/overloadable-attrs.cpp
new file mode 100644
index 000000000000..38c9558fe882
--- /dev/null
+++ b/test/Modules/overloadable-attrs.cpp
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I%S/Inputs/overloadable-attrs -fmodules \
+// RUN: -fmodule-map-file=%S/Inputs/overloadable-attrs/module.modulemap \
+// RUN: -fmodules-cache-path=%t -verify %s -std=c++11
+//
+// Ensures that we don't merge decls with attrs that we allow overloading on.
+//
+// expected-no-diagnostics
+
+#include "a.h"
+
+static_assert(enable_if_attrs::fn1() == 1, "");
+static_assert(enable_if_attrs::fn2() == 1, "");
+static_assert(enable_if_attrs::fn3(0) == 0, "");
+static_assert(enable_if_attrs::fn3(1) == 1, "");
+static_assert(enable_if_attrs::fn4(0) == 0, "");
+static_assert(enable_if_attrs::fn4(1) == 1, "");
+static_assert(enable_if_attrs::fn5(0) == 0, "");
+static_assert(enable_if_attrs::fn5(1) == 1, "");
+
+static_assert(pass_object_size_attrs::fn1(nullptr) == 1, "");
+static_assert(pass_object_size_attrs::fn2(nullptr) == 1, "");
diff --git a/test/Modules/pragma-pack.cpp b/test/Modules/pragma-pack.cpp
new file mode 100644
index 000000000000..96a880c6307b
--- /dev/null
+++ b/test/Modules/pragma-pack.cpp
@@ -0,0 +1,25 @@
+// RUN: rm -rf %t.cache %tlocal.cache
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fmodules \
+// RUN: -fimplicit-module-maps -x c++ -emit-module \
+// RUN: -fmodules-cache-path=%t.cache \
+// RUN: -fmodule-name=pragma_pack %S/Inputs/module.map
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fmodules \
+// RUN: -fimplicit-module-maps -x c++ -verify \
+// RUN: -fmodules-cache-path=%t.cache \
+// RUN: -I%S/Inputs %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fmodules \
+// RUN: -fmodules-local-submodule-visibility \
+// RUN: -fimplicit-module-maps -x c++ -emit-module \
+// RUN: -fmodules-cache-path=%tlocal.cache \
+// RUN: -fmodule-name=pragma_pack %S/Inputs/module.map
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fmodules \
+// RUN: -fmodules-local-submodule-visibility \
+// RUN: -fimplicit-module-maps -x c++ -verify \
+// RUN: -fmodules-cache-path=%tlocal.cache \
+// RUN: -I%S/Inputs %s
+
+// Check that we don't serialize pragma pack state until/unless including an
+// empty file from the same module (but different submodule) has no effect.
+#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 8}}
+#include "empty.h"
+#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 8}}
diff --git a/test/Modules/rebuild.m b/test/Modules/rebuild.m
index 40f2d47e09e8..150c2ce266e4 100644
--- a/test/Modules/rebuild.m
+++ b/test/Modules/rebuild.m
@@ -19,11 +19,10 @@
// RUN: diff %t/Module.size %t/Module.size.saved
// RUN: cp %t/Module.pcm %t/Module.pcm.saved.2
-// But the signature at least is expected to change, so we rebuild DependsOnModule.
-// NOTE: if we change how the signature is created, this test may need updating.
+// The signature is the hash of the PCM content, we will not rebuild rebuild DependsOnModule.
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs %s
// RUN: diff %t/Module.pcm %t/Module.pcm.saved.2
-// RUN: not diff %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved
+// RUN: diff %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved
// Rebuild Module, reset its timestamp, and verify its size hasn't changed
// RUN: rm %t/Module.pcm
@@ -34,10 +33,9 @@
// RUN: cp %t/Module.pcm %t/Module.pcm.saved.2
// Verify again with Module pre-imported.
-// NOTE: if we change how the signature is created, this test may need updating.
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs %s
// RUN: diff %t/Module.pcm %t/Module.pcm.saved.2
-// RUN: not diff %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved
+// RUN: diff %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved
#ifdef PREIMPORT
@import Module;
diff --git a/test/Modules/system-out-of-date-test.m b/test/Modules/system-out-of-date-test.m
new file mode 100644
index 000000000000..e78df7b3b3e7
--- /dev/null
+++ b/test/Modules/system-out-of-date-test.m
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t.cache
+// RUN: echo '@import X;' | \
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps \
+// RUN: -fmodules-cache-path=%t.cache -I%S/Inputs/system-out-of-date \
+// RUN: -fsyntax-only -x objective-c -
+//
+// Build something with different diagnostic options.
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps \
+// RUN: -fmodules-cache-path=%t.cache -I%S/Inputs/system-out-of-date \
+// RUN: -fsyntax-only %s -Wnon-modular-include-in-framework-module \
+// RUN: -Werror=non-modular-include-in-framework-module 2>&1 \
+// RUN: | FileCheck %s
+@import X;
+
+#import <Z.h>
+// CHECK: While building module 'Z' imported from
+// CHECK: {{.*}}Y-{{.*}}pcm' was validated as a system module and is now being imported as a non-system module
diff --git a/test/Modules/system_version.m b/test/Modules/system_version.m
deleted file mode 100644
index b1bc3609272e..000000000000
--- a/test/Modules/system_version.m
+++ /dev/null
@@ -1,31 +0,0 @@
-// Test checking that we're hashing a system version file in the
-// module hash.
-
-// First, build a system root.
-// RUN: rm -rf %t
-// RUN: mkdir -p %t/usr/include
-// RUN: cp %S/Inputs/Modified/A.h %t/usr/include
-// RUN: cp %S/Inputs/Modified/B.h %t/usr/include
-// RUN: cp %S/Inputs/Modified/module.map %t/usr/include
-
-// Run once with no system version file. We should end up with one module.
-// RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -fimplicit-module-maps -isysroot %t -I %t/usr/include %s -verify
-// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 1
-
-// Add a system version file and run again. We should now have two
-// module variants.
-// RUN: mkdir -p %t/System/Library/CoreServices
-// RUN: echo "hello" > %t/System/Library/CoreServices/SystemVersion.plist
-// RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -fimplicit-module-maps -isysroot %t -I %t/usr/include %s -verify
-// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 2
-
-// Change the system version file and run again. We should now have three
-// module variants.
-// RUN: mkdir -p %t/System/Library/CoreServices
-// RUN: echo "modules" > %t/System/Library/CoreServices/SystemVersion.plist
-// RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -fimplicit-module-maps -isysroot %t -I %t/usr/include %s -verify
-// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 3
-
-// expected-no-diagnostics
-@import ModA;
-
diff --git a/test/Modules/warning-mismatch.m b/test/Modules/warning-mismatch.m
new file mode 100644
index 000000000000..dd7c7f82ec69
--- /dev/null
+++ b/test/Modules/warning-mismatch.m
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t.cache
+// RUN: echo "@import Mismatch;" >%t.m
+// RUN: %clang_cc1 -Wno-system-headers -fdisable-module-hash \
+// RUN: -fmodules-cache-path=%t.cache -fmodules -fimplicit-module-maps \
+// RUN: -I%S/Inputs/warning-mismatch %t.m -fsyntax-only
+// RUN: %clang_cc1 -Wsystem-headers -fdisable-module-hash \
+// RUN: -fmodules-cache-path=%t.cache -fmodules -fimplicit-module-maps \
+// RUN: -I%S/Inputs/warning-mismatch %s -fsyntax-only
+
+// This testcase triggers a warning flag mismatch in an already validated
+// header.
+@import Mismatch;
+@import System;
diff --git a/test/OpenMP/cancel_messages.cpp b/test/OpenMP/cancel_messages.cpp
index e23b5c337bc8..f8bbe2c36bea 100644
--- a/test/OpenMP/cancel_messages.cpp
+++ b/test/OpenMP/cancel_messages.cpp
@@ -4,8 +4,16 @@ int main(int argc, char **argv) {
#pragma omp cancellation // expected-error {{expected an OpenMP directive}}
#pragma omp cancel // expected-error {{one of 'for', 'parallel', 'sections' or 'taskgroup' is expected}}
;
+#pragma omp parallel
+ {
+#pragma omp cancel // expected-error {{one of 'for', 'parallel', 'sections' or 'taskgroup' is expected}}
+ }
#pragma omp cancel parallel untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp cancel'}}
#pragma omp cancel unknown // expected-error {{one of 'for', 'parallel', 'sections' or 'taskgroup' is expected}}
+#pragma omp parallel
+ {
+#pragma omp cancel unknown // expected-error {{one of 'for', 'parallel', 'sections' or 'taskgroup' is expected}}
+ }
#pragma omp cancel sections( // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}}
#pragma omp cancel for, ) // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}}
#pragma omp cancel taskgroup() // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}}
diff --git a/test/OpenMP/cancellation_point_messages.cpp b/test/OpenMP/cancellation_point_messages.cpp
index 2324915e83f8..21b0e9c2fa2d 100644
--- a/test/OpenMP/cancellation_point_messages.cpp
+++ b/test/OpenMP/cancellation_point_messages.cpp
@@ -4,8 +4,16 @@ int main(int argc, char **argv) {
#pragma omp cancellation // expected-error {{expected an OpenMP directive}}
#pragma omp cancellation point // expected-error {{one of 'for', 'parallel', 'sections' or 'taskgroup' is expected}}
;
+#pragma omp parallel
+ {
+#pragma omp cancellation point // expected-error {{one of 'for', 'parallel', 'sections' or 'taskgroup' is expected}}
+ }
#pragma omp cancellation point parallel untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp cancellation point'}}
#pragma omp cancellation point unknown // expected-error {{one of 'for', 'parallel', 'sections' or 'taskgroup' is expected}}
+#pragma omp parallel
+ {
+#pragma omp cancellation point unknown // expected-error {{one of 'for', 'parallel', 'sections' or 'taskgroup' is expected}}
+ }
#pragma omp cancellation point sections( // expected-warning {{extra tokens at the end of '#pragma omp cancellation point' are ignored}}
#pragma omp cancellation point for, ) // expected-warning {{extra tokens at the end of '#pragma omp cancellation point' are ignored}}
#pragma omp cancellation point taskgroup() // expected-warning {{extra tokens at the end of '#pragma omp cancellation point' are ignored}}
diff --git a/test/OpenMP/declare_reduction_messages.cpp b/test/OpenMP/declare_reduction_messages.cpp
index a1373b1dcb9b..198d7756d035 100644
--- a/test/OpenMP/declare_reduction_messages.cpp
+++ b/test/OpenMP/declare_reduction_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 %s
int temp; // expected-note 7 {{'temp' declared here}}
@@ -51,7 +53,17 @@ class Class2 : public Class1<T> {
#pragma omp declare reduction(fun222 : long : omp_out += omp_in) // expected-error {{redefinition of user-defined reduction for type 'long'}}
#pragma omp declare reduction(fun1 : long : omp_out += omp_in) initializer // expected-error {{expected '(' after 'initializer'}}
#pragma omp declare reduction(fun2 : long : omp_out += omp_in) initializer { // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}}
-#pragma omp declare reduction(fun3 : long : omp_out += omp_in) initializer[ // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}}
+#pragma omp declare reduction(fun3 : long : omp_out += omp_in) initializer[
+#if __cplusplus <= 199711L
+// expected-error@-2 {{expected '(' after 'initializer'}}
+// expected-error@-3 {{expected expression}}
+// expected-warning@-4 {{extra tokens at the end of '#pragma omp declare reduction' are ignored}}
+#else
+// expected-error@-6 {{expected '(' after 'initializer'}}
+// expected-error@-7 {{expected variable name or 'this' in lambda capture list}}
+// expected-error@-8 {{expected ')'}}
+// expected-note@-9 {{to match this '('}}
+#endif
#pragma omp declare reduction(fun4 : long : omp_out += omp_in) initializer() // expected-error {{expected expression}}
#pragma omp declare reduction(fun5 : long : omp_out += omp_in) initializer(temp) // expected-error {{only 'omp_priv' or 'omp_orig' variables are allowed in initializer expression}}
#pragma omp declare reduction(fun6 : long : omp_out += omp_in) initializer(omp_orig // expected-error {{expected ')'}} expected-note {{to match this '('}}
diff --git a/test/OpenMP/distribute_collapse_messages.cpp b/test/OpenMP/distribute_collapse_messages.cpp
index 8818d659d441..4897e6931d27 100644
--- a/test/OpenMP/distribute_collapse_messages.cpp
+++ b/test/OpenMP/distribute_collapse_messages.cpp
@@ -1,8 +1,13 @@
// RUN: %clang_cc1 -verify -fopenmp %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s
void foo() {
}
+#if __cplusplus >= 201103L
+ // expected-note@+2 4 {{declared here}}
+#endif
bool foobool(int argc) {
return argc;
}
@@ -29,6 +34,9 @@ T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp distribute collapse ((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'collapse' clause}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp distribute', but found only 1}}
+#if __cplusplus >= 201103L
+ // expected-note@+5 2 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
// expected-error@+3 2 {{directive '#pragma omp distribute' cannot contain more than one 'collapse' clause}}
// expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
@@ -36,7 +44,11 @@ T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp distribute collapse (S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{expression is not an integral constant expression}}
+#if __cplusplus <= 199711L
+ // expected-error@+4 2 {{expression is not an integral constant expression}}
+#else
+ // expected-error@+2 2 {{integral constant expression must have integral or unscoped enumeration type, not 'char *'}}
+#endif
#pragma omp distribute collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp distribute collapse (1)
@@ -59,8 +71,14 @@ int main(int argc, char **argv) {
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp distribute', but found only 1}}
#pragma omp distribute collapse (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp distribute' are ignored}} expected-note {{as specified in 'collapse' clause}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp distribute', but found only 1}}
+#if __cplusplus >= 201103L
+ // expected-note@+2 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
#pragma omp distribute collapse (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+#if __cplusplus >= 201103L
+ // expected-note@+5 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp distribute' cannot contain more than one 'collapse' clause}}
// expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
@@ -68,7 +86,11 @@ int main(int argc, char **argv) {
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp distribute collapse (S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- // expected-error@+1 {{expression is not an integral constant expression}}
+#if __cplusplus <= 199711L
+ // expected-error@+4 {{expression is not an integral constant expression}}
+#else
+ // expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'char *'}}
+#endif
#pragma omp distribute collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{statement after '#pragma omp distribute' must be a for loop}}
diff --git a/test/OpenMP/distribute_firstprivate_codegen.cpp b/test/OpenMP/distribute_firstprivate_codegen.cpp
new file mode 100644
index 000000000000..718fc875254c
--- /dev/null
+++ b/test/OpenMP/distribute_firstprivate_codegen.cpp
@@ -0,0 +1,382 @@
+// RUN: %clang_cc1 -DLAMBDA -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix LAMBDA --check-prefix LAMBDA-64
+// RUN: %clang_cc1 -DLAMBDA -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DLAMBDA -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix LAMBDA --check-prefix LAMBDA-64
+// RUN: %clang_cc1 -DLAMBDA -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix LAMBDA --check-prefix LAMBDA-32
+// RUN: %clang_cc1 -DLAMBDA -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DLAMBDA -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix LAMBDA --check-prefix LAMBDA-32
+
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a) {}
+ S() : f() {}
+ operator T() { return T(); }
+ ~S() {}
+};
+
+// CHECK: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
+template <typename T>
+T tmain() {
+ S<T> test;
+ T t_var = T();
+ T vec[] = {1, 2};
+ S<T> s_arr[] = {1, 2};
+ S<T> &var = test;
+ #pragma omp target
+ #pragma omp teams
+#pragma omp distribute firstprivate(t_var, vec, s_arr, s_arr, var, var)
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
+ return T();
+}
+
+int main() {
+ static int svar;
+ volatile double g;
+ volatile double &g1 = g;
+
+ #ifdef LAMBDA
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call{{.*}} void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ static float sfvar;
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: call i{{[0-9]+}} @__tgt_target_teams(
+ // LAMBDA: call void [[OFFLOADING_FUN:@.+]](
+
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, {{.+}}, {{.+}}* [[OMP_OUTLINED:@.+]] to {{.+}})
+ #pragma omp target
+ #pragma omp teams
+#pragma omp distribute firstprivate(g, g1, svar, sfvar)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA-64: define{{.*}} internal{{.*}} void [[OMP_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, i{{[0-9]+}} [[G_IN:%.+]], i{{[0-9]+}} [[G1_IN:%.+]], i{{[0-9]+}} [[SVAR_IN:%.+]], i{{[0-9]+}} [[SFVAR_IN:%.+]])
+ // LAMBDA-32: define internal{{.*}} void [[OMP_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, double*{{.*}} [[G_IN:%.+]], i{{[0-9]+}} [[G1_IN:%.+]], i{{[0-9]+}} [[SVAR_IN:%.+]], i{{[0-9]+}} [[SFVAR_IN:%.+]])
+ // Private alloca's for conversion
+ // LAMBDA-64: [[G_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA-32: [[G_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[G1_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SVAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SFVAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G1_REF:%.+]] = alloca double*,
+ // LAMBDA: [[TMP:%.+]] = alloca double*,
+
+ // Actual private variables to be used in the body (tmp is used for the reference type)
+ // LAMBDA: [[G_PRIVATE:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIVATE:%.+]] = alloca double,
+ // LAMBDA: [[TMP_PRIVATE:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SFVAR_PRIVATE:%.+]] = alloca float,
+
+ // Store input parameter addresses into private alloca's for conversion
+ // LAMBDA-64: store i{{[0-9]+}} [[G_IN]], i{{[0-9]+}}* [[G_ADDR]],
+ // LAMBDA-32: store double* [[G_IN]], double** [[G_ADDR]],
+ // LAMBDA: store i{{[0-9]+}} [[G1_IN]], i{{[0-9]+}}* [[G1_ADDR]],
+ // LAMBDA: store i{{[0-9]+}} [[SVAR_IN]], i{{[0-9]+}}* [[SVAR_ADDR]],
+ // LAMBDA: store i{{[0-9]+}} [[SFVAR_IN]], i{{[0-9]+}}* [[SFVAR_ADDR]],
+
+ // LAMBDA-64-DAG: [[G_CONV:%.+]] = bitcast i{{[0-9]+}}* [[G_ADDR]] to double*
+ // LAMBDA-32-DAG: [[G_ADDR_VAL:%.+]] = load double*, double** [[G_ADDR]],
+ // LAMBDA-DAG: [[G1_CONV:%.+]] = bitcast i{{[0-9]+}}* [[G1_ADDR]] to double*
+ // LAMBDA-DAG: store double* [[G1_CONV]], double** [[G1_REF]],
+ // LAMBDA-64-DAG: [[SVAR_CONV:%.+]] = bitcast i{{[0-9]+}}* [[SVAR_ADDR]] to i{{[0-9]+}}*
+ // LAMBDA-DAG: [[SFVAR_CONV:%.+]] = bitcast i{{[0-9]+}}* [[SFVAR_ADDR]] to float*
+ // LAMBDA-DAG: [[G1_REF_VAL:%.+]] = load double*, double** [[G1_REF]],
+ // LAMBDA-DAG: store double* [[G1_REF_VAL]], double** [[TMP]],
+ // LAMBDA-64-DAG: [[G_CONV_VAL:%.+]] = load{{.*}} double, double* [[G_CONV]],
+ // LAMBDA-32-DAG: [[G_CONV_VAL:%.+]] = load{{.*}} double, double* [[G_ADDR_VAL]],
+ // LAMBDA-DAG: store double [[G_CONV_VAL]], double* [[G_PRIVATE]],
+ // LAMBDA-DAG: [[TMP_VAL:%.+]] = load double*, double** [[TMP]],
+ // LAMBDA-DAG: [[TMP_VAL_VAL:%.+]] = load{{.*}} double, double* [[TMP_VAL]],
+ // LAMBDA-DAG: store double [[TMP_VAL_VAL]], double* [[G1_PRIVATE]],
+ // LAMBDA-DAG: store double* [[G1_PRIVATE]], double** [[TMP_PRIVATE]],
+ // LAMBDA-64-DAG: [[SVAR_CONV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SVAR_CONV]],
+ // LAMBDA-32-DAG: [[SVAR_CONV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SVAR_ADDR]],
+ // LAMBDA-DAG: store i{{[0-9]+}} [[SVAR_CONV_VAL]], i{{[0-9]+}}* [[SVAR_PRIVATE]],
+ // LAMBDA-DAG: [[SFVAR_CONV_VAL:%.+]] = load float, float* [[SFVAR_CONV]],
+ // LAMBDA-DAG: store float [[SFVAR_CONV_VAL]], float* [[SFVAR_PRIVATE]],
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4(
+ g += 1;
+ g1 += 1;
+ svar += 3;
+ sfvar += 4.0;
+ // LAMBDA-DAG: [[G_VAL:%.+]] = load double, double* [[G_PRIVATE]],
+ // LAMBDA-DAG: [[G_NEXT:%.+]] = fadd double [[G_VAL]], 1.{{.+}}
+ // LAMBDA-DAG: store double [[G_NEXT]], double* [[G_PRIVATE]],
+ // LAMBDA-DAG: [[TMP_VAL1:%.+]] = load double*, double** [[TMP_PRIVATE]],
+ // LAMBDA-DAG: [[TMP_VAL_VAL1:%.+]] = load{{.*}} double, double* [[TMP_VAL1]],
+ // LAMBDA-DAG: [[TMP_ADD:%.+]] = fadd double [[TMP_VAL_VAL1]], 1.{{.+}}
+ // LAMBDA-DAG: store{{.*}} double [[TMP_ADD]], double* [[TMP_VAL1]],
+ // LAMBDA-DAG: [[SVAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SVAR_PRIVATE]],
+ // LAMBDA-DAG: [[SVAR_ADD:%.+]] = add{{.*}} i{{[0-9]+}} [[SVAR_VAL]], 3
+ // LAMBDA-DAG: store i{{[0-9]+}} [[SVAR_ADD]], i{{[0-9]+}}* [[SVAR_PRIVATE]],
+ // LAMBDA-DAG: [[SFVAR_VAL:%.+]] = load float, float* [[SFVAR_PRIVATE]],
+ // LAMBDA-DAG: [[SFVAR_CONV_VAL1:%.+]] = fpext float [[SFVAR_VAL]] to double
+ // LAMBDA-DAG: [[SFVAR_ADD:%.+]] = fadd double [[SFVAR_CONV_VAL1]], 4.{{.+}}
+ // LAMBDA-DAG: [[SFVAR_CONV_VAL2:%.+]] = fptrunc double [[SFVAR_ADD]] to float
+ // LAMBDA-DAG: store float [[SFVAR_CONV_VAL2:%.+]], float* [[SFVAR_PRIVATE]],
+
+ // call inner lambda (use refs to private alloca's)
+ // LAMBDA: [[GEP_0:%.+]] = getelementptr{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store double* [[G_PRIVATE]], double** [[GEP_0]],
+ // LAMBDA: [[GEP_1:%.+]] = getelementptr{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[TMP_PAR:%.+]] = load double*, double** [[TMP_PRIVATE]],
+ // LAMBDA: store double* [[TMP_PAR]], double** [[GEP_1]],
+ // LAMBDA: [[GEP_2:%.+]] = getelementptr{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: store i{{[0-9]+}}* [[SVAR_PRIVATE]], i{{[0-9]+}}** [[GEP_2]],
+ // LAMBDA: [[GEP_3:%.+]] = getelementptr{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: store float* [[SFVAR_PRIVATE]], float** [[GEP_3]],
+ // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* {{.+}})
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g += 2;
+ g1 += 2;
+ svar += 4;
+ sfvar += 8.0;
+ // LAMBDA-DAG: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA-DAG: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA-DAG: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]],
+ // LAMBDA-DAG: [[G_REF_VAL:%.+]] = load double, double* [[G_REF]],
+ // LAMBDA-DAG: [[G_REF_ADD:%.+]] = fadd double [[G_REF_VAL]], 2.{{.+}}
+ // LAMBDA-DAG: store double [[G_REF_ADD]], double* [[G_REF]]
+
+ // LAMBDA-DAG: [[TMP_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA-DAG: [[G1_REF:%.+]] = load double*, double** [[TMP_PTR_REF]]
+ // LAMBDA-DAG: [[G1_REF_VAL:%.+]] = load double, double* [[G1_REF]],
+ // LAMBDA-DAG: [[G1_ADD:%.+]] = fadd double [[G1_REF_VAL]], 2.{{.+}}
+ // LAMBDA-DAG: store double [[G1_ADD]], double* [[G1_REF]],
+
+ // LAMBDA-DAG: [[SVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA-DAG: [[SVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PTR_REF]]
+ // LAMBDA-DAG: [[SVAR_REF_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SVAR_REF]]
+ // LAMBDA-DAG: [[SVAR_ADD:%.+]] = add{{.*}} i{{[0-9]+}} [[SVAR_REF_VAL]], 4
+ // LAMBDA-DAG: store i{{[0-9]+}} [[SVAR_ADD]], i{{[0-9]+}}* [[SVAR_REF]]
+
+ // LAMBDA-DAG: [[SFVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA-DAG: [[SFVAR_REF:%.+]] = load float*, float** [[SFVAR_PTR_REF]]
+ // LAMBDA-DAG: [[SFVAR_REF_VAL:%.+]] = load float, float* [[SFVAR_REF]]
+ // LAMBDA-DAG: [[SFVAR_REF_CONV:%.+]] = fpext float [[SFVAR_REF_VAL]] to double
+ // LAMBDA-DAG: [[SFVAR_ADD:%.+]] = fadd double [[SFVAR_REF_CONV]], 8.{{.+}}
+ // LAMBDA-DAG: [[SFVAR_ADD_CONV:%.+]] = fptrunc double [[SFVAR_ADD]] to float
+ // LAMBDA-DAG: store float [[SFVAR_ADD_CONV]], float* [[SFVAR_REF]],
+ }();
+ }
+ }();
+ return 0;
+ #else
+ S<float> test;
+ int t_var = 0;
+ int vec[] = {1, 2};
+ S<float> s_arr[] = {1, 2};
+ S<float> &var = test;
+
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute firstprivate(t_var, vec, s_arr, s_arr, var, var, svar)
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
+ return tmain<int>();
+ #endif
+}
+
+// CHECK: define{{.*}} i{{[0-9]+}} @main()
+// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOAD_FUN:@.+]](
+// CHECK: ret
+
+// CHECK: define{{.+}} [[OFFLOAD_FUN]](
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_teams(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i{{[0-9]+}}, [2 x i{{[0-9]+}}]*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]*, i{{[0-9]+}})* [[OMP_OUTLINED:@.+]] to void
+// CHECK: ret
+//
+// CHECK: define internal void [[OMP_OUTLINED]](i{{[0-9]+}}*{{.+}}, i{{[0-9]+}}*{{.+}}, i{{[0-9]+}} [[T_VAR_IN:%.+]], [2 x i{{[0-9]+}}]*{{.*}} [[VEC_IN:%.+]], [2 x [[S_FLOAT_TY]]]*{{.*}} [[S_ARR_IN:%.+]], [[S_FLOAT_TY]]*{{.*}} [[VAR_IN:%.+]], i{{[0-9]+}} [[SVAR_IN:%.+]])
+
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[S_ARR_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR_ADDR:%.+]] = alloca [[S_FLOAT_TY]]*,
+// CHECK: [[SVAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[TMP:%.+]] = alloca [[S_FLOAT_TY]]*,
+
+// discard omp loop variables
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+
+// CHECK-DAG: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK-DAG: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK-DAG: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK-DAG: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK-DAG: [[TMP_PRIV:%.+]] = alloca [[S_FLOAT_TY]]*,
+// CHECK: [[SVAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+
+// CHECK: store i{{[0-9]+}} [[T_VAR_IN]], i{{[0-9]+}}* [[T_VAR_ADDR]],
+// CHECK: store [2 x i{{[0-9]+}}]* [[VEC_IN]], [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: store [2 x [[S_FLOAT_TY]]]* [[S_ARR_IN]], [2 x [[S_FLOAT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: store [[S_FLOAT_TY]]* [[VAR_IN]], [[S_FLOAT_TY]]** [[VAR_ADDR]],
+// CHECK: store i{{[0-9]+}} [[SVAR_IN]], i{{[0-9]+}}* [[SVAR_ADDR]],
+
+// init t_var
+// CHECK-64-DAG: [[T_VAR_ADDR_CONV:%.+]] = bitcast i{{[0-9]+}}* [[T_VAR_ADDR]] to i{{[0-9]+}}*
+// CHECK-64-DAG: [[T_VAR_ADDR_CONV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_ADDR_CONV]],
+// CHECK-32-DAG: [[T_VAR_ADDR_CONV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_ADDR]],
+// CHECK-DAG: store i{{[0-9]+}} [[T_VAR_ADDR_CONV_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
+
+// init vec
+// CHECK-DAG: [[VEC_ADDR_VAL:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK-DAG: [[VEC_ADDR_VAL_BCAST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_VAL]] to i{{[0-9]+}}*
+// CHECK-DAG: [[VEC_PRIV_BCAST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i{{[0-9]+}}*
+// CHECK-DAG: call void @llvm.memcpy.{{.*}}(i{{[0-9]+}}* [[VEC_PRIV_BCAST]], i{{[0-9]+}}* [[VEC_ADDR_VAL_BCAST]],{{.+}})
+
+// init s_arr
+// CHECK-DAG: [[S_ARR_ADDR_VAL:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[S_ARR_ADDR]],
+// CHECK-DAG: [[S_ARR_ADDR_BCAST:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[S_ARR_ADDR_VAL]] to [[S_FLOAT_TY]]*
+// CHECK-DAG: [[S_ARR_PRIV_BGN:%.+]] = getelementptr{{.+}} [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]]{{.+}}
+// CHECK-DAG: [[S_ARR_PRIV_NEXT:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_PRIV_BGN]]{{.+}}
+// CHECK-DAG: [[S_ARR_IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_PRIV_BGN]], [[S_ARR_PRIV_NEXT]]
+// CHECK-DAG: br i1 [[S_ARR_IS_EMPTY]], label %[[S_ARR_CPY_DONE:.+]], label %[[S_ARR_CPY_BODY:.+]]
+
+// CHECK-DAG: [[S_ARR_CPY_BODY]]:
+// CHECK-DAG: [[S_ARR_SRC_PAST:%.+]] = phi{{.+}} [ [[S_ARR_ADDR_BCAST]],{{.+}} ], [ [[S_ARR_SRC:%.+]],{{.+}} ]
+// CHECK-DAG: [[S_ARR_DST_PAST:%.+]] = phi{{.+}} [ [[S_ARR_PRIV_BGN]],{{.+}} ], [ [[S_ARR_DST:%.+]],{{.+}} ]
+// CHECK-DAG: [[S_ARR_SRC_BCAST:%.+]] = bitcast{{.+}} [[S_ARR_SRC_PAST]] to{{.+}}
+// CHECK-DAG: [[S_ARR_DST_BCAST:%.+]] = bitcast{{.+}} [[S_ARR_DST_PAST]] to{{.+}}
+// CHECK-DAG: call{{.+}} @llvm.memcpy.{{.+}}({{.+}}* [[S_ARR_DST_BCAST]], {{.+}}* [[S_ARR_SRC_BCAST]]{{.+}})
+// CHECK-DAG: [[S_ARR_SRC]] = getelementptr{{.+}}
+// CHECK-DAG: [[S_ARR_DST]] = getelementptr{{.+}}
+// CHECK-DAG: [[S_ARR_CPY_FIN:%.+]] = icmp{{.+}} [[S_ARR_DST]], [[S_ARR_PRIV_NEXT]]
+// CHECK-DAG: br i1 [[S_ARR_CPY_FIN]], label %[[S_ARR_CPY_DONE]], label %[[S_ARR_CPY_BODY]]
+// CHECK-DAG: [[S_ARR_CPY_DONE]]:
+
+// init var
+// CHECK-DAG: [[VAR_ADDR_VAL:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_ADDR]],
+// CHECK-DAG: store{{.+}} [[VAR_ADDR_VAL]],{{.+}} [[TMP]],
+// CHECK-DAG: [[TMP_VAL:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[TMP]],
+// CHECK-DAG: [[VAR_PRIV_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_PRIV]] to{{.+}}
+// CHECK-DAG: [[TMP_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[TMP_VAL]] to{{.+}}
+// CHECK-DAG: call{{.+}} @llvm.memcpy.{{.+}}({{.+}}* [[VAR_PRIV_BCAST]], {{.+}}* [[TMP_BCAST]],{{.+}})
+// CHECK-DAG: store [[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]** [[TMP_PRIV]],
+
+// init svar
+// CHECK-64-DAG: [[SVAR_ADDR_CONV:%.+]] = bitcast{{.+}} [[SVAR_ADDR]] to{{.+}}
+// CHECK-64-DAG: [[SVAR_CONV_VAL:%.+]] = load{{.+}},{{.+}} [[SVAR_ADDR_CONV]],
+// CHECK-32-DAG: [[SVAR_CONV_VAL:%.+]] = load{{.+}},{{.+}} [[SVAR_ADDR]],
+// CHECK-DAG: store{{.+}} [[SVAR_CONV_VAL]],{{.+}} [[SVAR_PRIV]],
+
+// CHECK-DAG: store i{{[0-9]+}} 0, i{{[0-9]+}}* %.omp{{.+}},
+// CHECK-DAG: store i{{[0-9]+}} 1, i{{[0-9]+}}* %.omp{{.+}},
+// CHECK-DAG: store i{{[0-9]+}} 1, i{{[0-9]+}}* %.omp{{.+}},
+// CHECK-DAG: store i{{[0-9]+}} 0, i{{[0-9]+}}* %.omp{{.+}},
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+
+// Template
+// CHECK: define{{.*}} i{{[0-9]+}} [[TMAIN_INT:@.+]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOAD_FUN_1:@.+]](
+// CHECK: ret
+
+// CHECK: define{{.+}} [[OFFLOAD_FUN_1]](
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_teams(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i{{[0-9]+}}, [2 x i{{[0-9]+}}]*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[OMP_OUTLINED_1:@.+]] to void
+// CHECK: ret
+//
+// CHECK: define internal void [[OMP_OUTLINED_1]](i{{[0-9]+}}*{{.+}}, i{{[0-9]+}}*{{.+}}, i{{[0-9]+}} [[T_VAR_IN:%.+]], [2 x i{{[0-9]+}}]*{{.*}} [[VEC_IN:%.+]], [2 x [[S_INT_TY]]]*{{.*}} [[S_ARR_IN:%.+]], [[S_INT_TY]]*{{.*}} [[VAR_IN:%.+]])
+
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[S_ARR_ADDR:%.+]] = alloca [2 x [[S_INT_TY]]]*,
+// CHECK: [[VAR_ADDR:%.+]] = alloca [[S_INT_TY]]*,
+// CHECK: [[TMP:%.+]] = alloca [[S_INT_TY]]*,
+
+// discard omp loop variables
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+// CHECK: {{.*}} = alloca i{{[0-9]+}},
+
+// CHECK-DAG: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK-DAG: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK-DAG: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK-DAG: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK-DAG: [[TMP_PRIV:%.+]] = alloca [[S_INT_TY]]*,
+
+// CHECK: store i{{[0-9]+}} [[T_VAR_IN]], i{{[0-9]+}}* [[T_VAR_ADDR]],
+// CHECK: store [2 x i{{[0-9]+}}]* [[VEC_IN]], [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: store [2 x [[S_INT_TY]]]* [[S_ARR_IN]], [2 x [[S_INT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: store [[S_INT_TY]]* [[VAR_IN]], [[S_INT_TY]]** [[VAR_ADDR]],
+
+// init t_var
+// CHECK-64-DAG: [[T_VAR_ADDR_CONV:%.+]] = bitcast i{{[0-9]+}}* [[T_VAR_ADDR]] to i{{[0-9]+}}*
+// CHECK-64-DAG: [[T_VAR_ADDR_CONV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_ADDR_CONV]],
+// CHECK-32-DAG: [[T_VAR_ADDR_CONV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_ADDR]],
+// CHECK-DAG: store i{{[0-9]+}} [[T_VAR_ADDR_CONV_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
+
+// init vec
+// CHECK-DAG: [[VEC_ADDR_VAL:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK-DAG: [[VEC_ADDR_VAL_BCAST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_VAL]] to i{{[0-9]+}}*
+// CHECK-DAG: [[VEC_PRIV_BCAST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i{{[0-9]+}}*
+// CHECK-DAG: call void @llvm.memcpy.{{.*}}(i{{[0-9]+}}* [[VEC_PRIV_BCAST]], i{{[0-9]+}}* [[VEC_ADDR_VAL_BCAST]],{{.+}})
+
+// init s_arr
+// CHECK-DAG: [[S_ARR_ADDR_VAL:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[S_ARR_ADDR]],
+// CHECK-DAG: [[S_ARR_ADDR_BCAST:%.+]] = bitcast [2 x [[S_INT_TY]]]* [[S_ARR_ADDR_VAL]] to [[S_INT_TY]]*
+// CHECK-DAG: [[S_ARR_PRIV_BGN:%.+]] = getelementptr{{.+}} [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]]{{.+}}
+// CHECK-DAG: [[S_ARR_PRIV_NEXT:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_PRIV_BGN]]{{.+}}
+// CHECK-DAG: [[S_ARR_IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_PRIV_BGN]], [[S_ARR_PRIV_NEXT]]
+// CHECK-DAG: br i1 [[S_ARR_IS_EMPTY]], label %[[S_ARR_CPY_DONE:.+]], label %[[S_ARR_CPY_BODY:.+]]
+
+// CHECK-DAG: [[S_ARR_CPY_BODY]]:
+// CHECK-DAG: [[S_ARR_SRC_PAST:%.+]] = phi{{.+}} [ [[S_ARR_ADDR_BCAST]],{{.+}} ], [ [[S_ARR_SRC:%.+]],{{.+}} ]
+// CHECK-DAG: [[S_ARR_DST_PAST:%.+]] = phi{{.+}} [ [[S_ARR_PRIV_BGN]],{{.+}} ], [ [[S_ARR_DST:%.+]],{{.+}} ]
+// CHECK-DAG: [[S_ARR_SRC_BCAST:%.+]] = bitcast{{.+}} [[S_ARR_SRC_PAST]] to{{.+}}
+// CHECK-DAG: [[S_ARR_DST_BCAST:%.+]] = bitcast{{.+}} [[S_ARR_DST_PAST]] to{{.+}}
+// CHECK-DAG: call{{.+}} @llvm.memcpy.{{.+}}({{.+}}* [[S_ARR_DST_BCAST]], {{.+}}* [[S_ARR_SRC_BCAST]]{{.+}})
+// CHECK-DAG: [[S_ARR_SRC]] = getelementptr{{.+}}
+// CHECK-DAG: [[S_ARR_DST]] = getelementptr{{.+}}
+// CHECK-DAG: [[S_ARR_CPY_FIN:%.+]] = icmp{{.+}} [[S_ARR_DST]], [[S_ARR_PRIV_NEXT]]
+// CHECK-DAG: br i1 [[S_ARR_CPY_FIN]], label %[[S_ARR_CPY_DONE]], label %[[S_ARR_CPY_BODY]]
+// CHECK-DAG: [[S_ARR_CPY_DONE]]:
+
+// init var
+// CHECK-DAG: [[VAR_ADDR_VAL:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_ADDR]],
+// CHECK-DAG: store{{.+}} [[VAR_ADDR_VAL]],{{.+}} [[TMP]],
+// CHECK-DAG: [[TMP_VAL:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TMP]],
+// CHECK-DAG: [[VAR_PRIV_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[VAR_PRIV]] to{{.+}}
+// CHECK-DAG: [[TMP_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[TMP_VAL]] to{{.+}}
+// CHECK-DAG: call{{.+}} @llvm.memcpy.{{.+}}({{.+}}* [[VAR_PRIV_BCAST]], {{.+}}* [[TMP_BCAST]],{{.+}})
+// CHECK-DAG: store [[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]** [[TMP_PRIV]],
+
+// CHECK-DAG: store i{{[0-9]+}} 0, i{{[0-9]+}}* %.omp{{.+}},
+// CHECK-DAG: store i{{[0-9]+}} 1, i{{[0-9]+}}* %.omp{{.+}},
+// CHECK-DAG: store i{{[0-9]+}} 1, i{{[0-9]+}}* %.omp{{.+}},
+// CHECK-DAG: store i{{[0-9]+}} 0, i{{[0-9]+}}* %.omp{{.+}},
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+#endif
diff --git a/test/OpenMP/distribute_lastprivate_codegen.cpp b/test/OpenMP/distribute_lastprivate_codegen.cpp
index 0f596defbfe9..abcbfd8d69c4 100644
--- a/test/OpenMP/distribute_lastprivate_codegen.cpp
+++ b/test/OpenMP/distribute_lastprivate_codegen.cpp
@@ -229,8 +229,6 @@ int main() {
// the distribute loop
// CHECK: call void @__kmpc_for_static_init_4(
// assignment: vec[i] = t_var;
-// the following is extremely weak, because it assumes ordering of this load with no reference after the call to static_init: fix!!!!
-// CHECK: [[IV_VAL:%.+]] =
// CHECK: [[T_VAR_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
// CHECK: [[VEC_PTR:%.+]] = getelementptr inbounds [2 x i{{[0-9]+}}], [2 x i{{[0-9]+}}]* [[VEC_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} {{.+}}
// CHECK: store i{{[0-9]+}} [[T_VAR_PRIV_VAL]], i{{[0-9]+}}* [[VEC_PTR]],
diff --git a/test/OpenMP/linking.c b/test/OpenMP/linking.c
index 7b3059242370..71e978f7fe48 100644
--- a/test/OpenMP/linking.c
+++ b/test/OpenMP/linking.c
@@ -7,42 +7,42 @@
// RUN: -fopenmp -target i386-unknown-linux -rtlib=platform \
// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}"
-// CHECK-LD-32: "-l[[DEFAULT_OPENMP_LIB:[^"]*]]" "-lgcc"
+// CHECK-LD-32: "-l[[DEFAULT_OPENMP_LIB:[^"]*]]"
// CHECK-LD-32: "-lpthread" "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -fopenmp -target x86_64-unknown-linux -rtlib=platform \
// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}"
-// CHECK-LD-64: "-l[[DEFAULT_OPENMP_LIB:[^"]*]]" "-lgcc"
+// CHECK-LD-64: "-l[[DEFAULT_OPENMP_LIB:[^"]*]]"
// CHECK-LD-64: "-lpthread" "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -fopenmp=libgomp -target i386-unknown-linux -rtlib=platform \
// RUN: | FileCheck --check-prefix=CHECK-GOMP-LD-32 %s
// CHECK-GOMP-LD-32: "{{.*}}ld{{(.exe)?}}"
-// CHECK-GOMP-LD-32: "-lgomp" "-lrt" "-lgcc"
+// CHECK-GOMP-LD-32: "-lgomp" "-lrt"
// CHECK-GOMP-LD-32: "-lpthread" "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -fopenmp=libgomp -target x86_64-unknown-linux -rtlib=platform \
// RUN: | FileCheck --check-prefix=CHECK-GOMP-LD-64 %s
// CHECK-GOMP-LD-64: "{{.*}}ld{{(.exe)?}}"
-// CHECK-GOMP-LD-64: "-lgomp" "-lrt" "-lgcc"
+// CHECK-GOMP-LD-64: "-lgomp" "-lrt"
// CHECK-GOMP-LD-64: "-lpthread" "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -fopenmp -target i386-unknown-linux -rtlib=platform \
// RUN: | FileCheck --check-prefix=CHECK-IOMP5-LD-32 %s
// CHECK-IOMP5-LD-32: "{{.*}}ld{{(.exe)?}}"
-// CHECK-IOMP5-LD-32: "-l[[DEFAULT_OPENMP_LIB:[^"]*]]" "-lgcc"
+// CHECK-IOMP5-LD-32: "-l[[DEFAULT_OPENMP_LIB:[^"]*]]"
// CHECK-IOMP5-LD-32: "-lpthread" "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -fopenmp -target x86_64-unknown-linux -rtlib=platform \
// RUN: | FileCheck --check-prefix=CHECK-IOMP5-LD-64 %s
// CHECK-IOMP5-LD-64: "{{.*}}ld{{(.exe)?}}"
-// CHECK-IOMP5-LD-64: "-l[[DEFAULT_OPENMP_LIB:[^"]*]]" "-lgcc"
+// CHECK-IOMP5-LD-64: "-l[[DEFAULT_OPENMP_LIB:[^"]*]]"
// CHECK-IOMP5-LD-64: "-lpthread" "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
@@ -60,7 +60,7 @@
// RUN: -rtlib=platform \
// RUN: | FileCheck --check-prefix=CHECK-LD-OVERRIDE-32 %s
// CHECK-LD-OVERRIDE-32: "{{.*}}ld{{(.exe)?}}"
-// CHECK-LD-OVERRIDE-32: "-lgomp" "-lrt" "-lgcc"
+// CHECK-LD-OVERRIDE-32: "-lgomp" "-lrt"
// CHECK-LD-OVERRIDE-32: "-lpthread" "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
@@ -68,7 +68,7 @@
// RUN: -rtlib=platform \
// RUN: | FileCheck --check-prefix=CHECK-LD-OVERRIDE-64 %s
// CHECK-LD-OVERRIDE-64: "{{.*}}ld{{(.exe)?}}"
-// CHECK-LD-OVERRIDE-64: "-lgomp" "-lrt" "-lgcc"
+// CHECK-LD-OVERRIDE-64: "-lgomp" "-lrt"
// CHECK-LD-OVERRIDE-64: "-lpthread" "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
diff --git a/test/OpenMP/nvptx_target_codegen.cpp b/test/OpenMP/nvptx_target_codegen.cpp
index 59c4d5b277ce..dab0c5a082a5 100644
--- a/test/OpenMP/nvptx_target_codegen.cpp
+++ b/test/OpenMP/nvptx_target_codegen.cpp
@@ -8,6 +8,14 @@
#ifndef HEADER
#define HEADER
+// Check that the execution mode of all 6 target regions is set to Generic Mode.
+// CHECK-DAG: {{@__omp_offloading_.+l98}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l175}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l284}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l321}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l339}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l304}}_exec_mode = weak constant i8 1
+
template<typename tx, typename ty>
struct TT{
tx X;
@@ -23,7 +31,7 @@ int foo(int n) {
double cn[5][n];
TT<long long, char> d;
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l90}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l98}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -54,7 +62,7 @@ int foo(int n) {
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T1:@__omp_offloading_.+foo.+l90]]()
+ // CHECK: define {{.*}}void [[T1:@__omp_offloading_.+foo.+l98]]()
// CHECK-DAG: [[TID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
// CHECK-DAG: [[NTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
// CHECK-DAG: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
@@ -96,7 +104,7 @@ int foo(int n) {
{
}
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l167}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l175}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -127,7 +135,7 @@ int foo(int n) {
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T2:@__omp_offloading_.+foo.+l167]](i[[SZ:32|64]] [[ARG1:%[a-zA-Z_]+]])
+ // CHECK: define {{.*}}void [[T2:@__omp_offloading_.+foo.+l175]](i[[SZ:32|64]] [[ARG1:%[a-zA-Z_]+]])
// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]],
// CHECK: store i[[SZ]] [[ARG1]], i[[SZ]]* [[AA_ADDR]],
// CHECK: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
@@ -169,7 +177,7 @@ int foo(int n) {
aa += 1;
}
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l276}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l284}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -200,7 +208,7 @@ int foo(int n) {
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T3:@__omp_offloading_.+foo.+l276]](i[[SZ]]
+ // CHECK: define {{.*}}void [[T3:@__omp_offloading_.+foo.+l284]](i[[SZ]]
// Create local storage for each capture.
// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
// CHECK: [[LOCAL_B:%.+]] = alloca [10 x float]*
@@ -353,7 +361,7 @@ int bar(int n){
return a;
}
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+static.+313}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+static.+321}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -384,7 +392,7 @@ int bar(int n){
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T4:@__omp_offloading_.+static.+l313]](i[[SZ]]
+ // CHECK: define {{.*}}void [[T4:@__omp_offloading_.+static.+l321]](i[[SZ]]
// Create local storage for each capture.
// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
@@ -439,7 +447,7 @@ int bar(int n){
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+S1.+l331}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+S1.+l339}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -470,7 +478,7 @@ int bar(int n){
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T5:@__omp_offloading_.+S1.+l331]](
+ // CHECK: define {{.*}}void [[T5:@__omp_offloading_.+S1.+l339]](
// Create local storage for each capture.
// CHECK: [[LOCAL_THIS:%.+]] = alloca [[S1:%struct.*]]*
// CHECK: [[LOCAL_B:%.+]] = alloca i[[SZ]]
@@ -529,7 +537,7 @@ int bar(int n){
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l296}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l304}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -560,7 +568,7 @@ int bar(int n){
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T6:@__omp_offloading_.+template.+l296]](i[[SZ]]
+ // CHECK: define {{.*}}void [[T6:@__omp_offloading_.+template.+l304]](i[[SZ]]
// Create local storage for each capture.
// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
diff --git a/test/OpenMP/nvptx_target_parallel_codegen.cpp b/test/OpenMP/nvptx_target_parallel_codegen.cpp
new file mode 100644
index 000000000000..7d1662435842
--- /dev/null
+++ b/test/OpenMP/nvptx_target_parallel_codegen.cpp
@@ -0,0 +1,136 @@
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -fexceptions -fcxx-exceptions -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// Check that the execution mode of all 2 target regions on the gpu is set to SPMD Mode.
+// CHECK-DAG: {{@__omp_offloading_.+l26}}_exec_mode = weak constant i8 0
+// CHECK-DAG: {{@__omp_offloading_.+l31}}_exec_mode = weak constant i8 0
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+ short aa = 0;
+ tx b[10];
+
+ #pragma omp target parallel if(target: 0)
+ {
+ a += 1;
+ }
+
+ #pragma omp target parallel map(tofrom: aa)
+ {
+ aa += 1;
+ }
+
+ #pragma omp target parallel map(tofrom:a, aa, b) if(target: n>40)
+ {
+ a += 1;
+ aa += 1;
+ b[2] += 1;
+ }
+
+ return a;
+}
+
+int bar(int n){
+ int a = 0;
+
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+ // CHECK-NOT: define {{.*}}void {{@__omp_offloading_.+template.+l17}}
+
+
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l26}}(
+ // CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
+ // CHECK: store i16* {{%.+}}, i16** [[AA_ADDR]], align
+ // CHECK: [[AA:%.+]] = load i16*, i16** [[AA_ADDR]], align
+ // CHECK: [[THREAD_LIMIT:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK: call void @__kmpc_spmd_kernel_init(i32 [[THREAD_LIMIT]],
+ // CHECK: br label {{%?}}[[EXEC:.+]]
+ //
+ // CHECK: [[EXEC]]
+ // CHECK: {{call|invoke}} void [[OP1:@.+]](i32* null, i32* null, i16* [[AA]])
+ // CHECK: br label {{%?}}[[DONE:.+]]
+ //
+ // CHECK: [[DONE]]
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+ // CHECK: }
+
+ // CHECK: define internal void [[OP1]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i16* {{[^%]*}}[[ARG:%.+]])
+ // CHECK: = alloca i32*, align
+ // CHECK: = alloca i32*, align
+ // CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
+ // CHECK: store i16* [[ARG]], i16** [[AA_ADDR]], align
+ // CHECK: [[AA:%.+]] = load i16*, i16** [[AA_ADDR]], align
+ // CHECK: [[VAL:%.+]] = load i16, i16* [[AA]], align
+ // CHECK: store i16 {{%.+}}, i16* [[AA]], align
+ // CHECK: ret void
+ // CHECK: }
+
+
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l31}}(
+ // CHECK: [[A_ADDR:%.+]] = alloca i32*, align
+ // CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
+ // CHECK: [[B_ADDR:%.+]] = alloca [10 x i32]*, align
+ // CHECK: store i32* {{%.+}}, i32** [[A_ADDR]], align
+ // CHECK: store i16* {{%.+}}, i16** [[AA_ADDR]], align
+ // CHECK: store [10 x i32]* {{%.+}}, [10 x i32]** [[B_ADDR]], align
+ // CHECK: [[A:%.+]] = load i32*, i32** [[A_ADDR]], align
+ // CHECK: [[AA:%.+]] = load i16*, i16** [[AA_ADDR]], align
+ // CHECK: [[B:%.+]] = load [10 x i32]*, [10 x i32]** [[B_ADDR]], align
+ // CHECK: [[THREAD_LIMIT:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK: call void @__kmpc_spmd_kernel_init(i32 [[THREAD_LIMIT]],
+ // CHECK: br label {{%?}}[[EXEC:.+]]
+ //
+ // CHECK: [[EXEC]]
+ // CHECK: {{call|invoke}} void [[OP2:@.+]](i32* null, i32* null, i32* [[A]], i16* [[AA]], [10 x i32]* [[B]])
+ // CHECK: br label {{%?}}[[DONE:.+]]
+ //
+ // CHECK: [[DONE]]
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+ // CHECK: }
+
+ // CHECK: define internal void [[OP2]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* {{[^%]*}}[[ARG1:%.+]], i16* {{[^%]*}}[[ARG2:%.+]], [10 x i32]* {{[^%]*}}[[ARG3:%.+]])
+ // CHECK: = alloca i32*, align
+ // CHECK: = alloca i32*, align
+ // CHECK: [[A_ADDR:%.+]] = alloca i32*, align
+ // CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
+ // CHECK: [[B_ADDR:%.+]] = alloca [10 x i32]*, align
+ // CHECK: store i32* [[ARG1]], i32** [[A_ADDR]], align
+ // CHECK: store i16* [[ARG2]], i16** [[AA_ADDR]], align
+ // CHECK: store [10 x i32]* [[ARG3]], [10 x i32]** [[B_ADDR]], align
+ // CHECK: [[A:%.+]] = load i32*, i32** [[A_ADDR]], align
+ // CHECK: [[AA:%.+]] = load i16*, i16** [[AA_ADDR]], align
+ // CHECK: [[B:%.+]] = load [10 x i32]*, [10 x i32]** [[B_ADDR]], align
+ // CHECK: store i32 {{%.+}}, i32* [[A]], align
+ // CHECK: store i16 {{%.+}}, i16* [[AA]], align
+ // CHECK: [[ELT:%.+]] = getelementptr inbounds [10 x i32], [10 x i32]* [[B]],
+ // CHECK: store i32 {{%.+}}, i32* [[ELT]], align
+ // CHECK: ret void
+ // CHECK: }
+#endif
diff --git a/test/OpenMP/nvptx_target_parallel_num_threads_codegen.cpp b/test/OpenMP/nvptx_target_parallel_num_threads_codegen.cpp
new file mode 100644
index 000000000000..bc423c1ee605
--- /dev/null
+++ b/test/OpenMP/nvptx_target_parallel_num_threads_codegen.cpp
@@ -0,0 +1,126 @@
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -fexceptions -fcxx-exceptions -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// Check that the execution mode of all 2 target regions on the gpu is set to SPMD Mode.
+// CHECK-DAG: {{@__omp_offloading_.+l21}}_exec_mode = weak constant i8 0
+// CHECK-DAG: {{@__omp_offloading_.+l26}}_exec_mode = weak constant i8 0
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+ short aa = 0;
+ tx b[10];
+
+ #pragma omp target parallel map(tofrom: aa) num_threads(1024)
+ {
+ aa += 1;
+ }
+
+ #pragma omp target parallel map(tofrom:a, aa, b) if(target: n>40) num_threads(n)
+ {
+ a += 1;
+ aa += 1;
+ b[2] += 1;
+ }
+
+ return a;
+}
+
+int bar(int n){
+ int a = 0;
+
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l21}}(
+ // CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
+ // CHECK: store i16* {{%.+}}, i16** [[AA_ADDR]], align
+ // CHECK: [[AA:%.+]] = load i16*, i16** [[AA_ADDR]], align
+ // CHECK: [[THREAD_LIMIT:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK: call void @__kmpc_spmd_kernel_init(i32 [[THREAD_LIMIT]],
+ // CHECK: br label {{%?}}[[EXEC:.+]]
+ //
+ // CHECK: [[EXEC]]
+ // CHECK-NOT: call void @__kmpc_push_num_threads
+ // CHECK: {{call|invoke}} void [[OP1:@.+]](i32* null, i32* null, i16* [[AA]])
+ // CHECK: br label {{%?}}[[DONE:.+]]
+ //
+ // CHECK: [[DONE]]
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+ // CHECK: }
+
+ // CHECK: define internal void [[OP1]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i16* {{[^%]*}}[[ARG:%.+]])
+ // CHECK: = alloca i32*, align
+ // CHECK: = alloca i32*, align
+ // CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
+ // CHECK: store i16* [[ARG]], i16** [[AA_ADDR]], align
+ // CHECK: [[AA:%.+]] = load i16*, i16** [[AA_ADDR]], align
+ // CHECK: [[VAL:%.+]] = load i16, i16* [[AA]], align
+ // CHECK: store i16 {{%.+}}, i16* [[AA]], align
+ // CHECK: ret void
+ // CHECK: }
+
+
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l26}}(
+ // CHECK: [[A_ADDR:%.+]] = alloca i32*, align
+ // CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
+ // CHECK: [[B_ADDR:%.+]] = alloca [10 x i32]*, align
+ // CHECK: store i32* {{%.+}}, i32** [[A_ADDR]], align
+ // CHECK: store i16* {{%.+}}, i16** [[AA_ADDR]], align
+ // CHECK: store [10 x i32]* {{%.+}}, [10 x i32]** [[B_ADDR]], align
+ // CHECK: [[A:%.+]] = load i32*, i32** [[A_ADDR]], align
+ // CHECK: [[AA:%.+]] = load i16*, i16** [[AA_ADDR]], align
+ // CHECK: [[B:%.+]] = load [10 x i32]*, [10 x i32]** [[B_ADDR]], align
+ // CHECK: [[THREAD_LIMIT:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK: call void @__kmpc_spmd_kernel_init(i32 [[THREAD_LIMIT]],
+ // CHECK: br label {{%?}}[[EXEC:.+]]
+ //
+ // CHECK: [[EXEC]]
+ // CHECK-NOT: call void @__kmpc_push_num_threads
+ // CHECK: {{call|invoke}} void [[OP2:@.+]](i32* null, i32* null, i32* [[A]], i16* [[AA]], [10 x i32]* [[B]])
+ // CHECK: br label {{%?}}[[DONE:.+]]
+ //
+ // CHECK: [[DONE]]
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+ // CHECK: }
+
+ // CHECK: define internal void [[OP2]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* {{[^%]*}}[[ARG1:%.+]], i16* {{[^%]*}}[[ARG2:%.+]], [10 x i32]* {{[^%]*}}[[ARG3:%.+]])
+ // CHECK: = alloca i32*, align
+ // CHECK: = alloca i32*, align
+ // CHECK: [[A_ADDR:%.+]] = alloca i32*, align
+ // CHECK: [[AA_ADDR:%.+]] = alloca i16*, align
+ // CHECK: [[B_ADDR:%.+]] = alloca [10 x i32]*, align
+ // CHECK: store i32* [[ARG1]], i32** [[A_ADDR]], align
+ // CHECK: store i16* [[ARG2]], i16** [[AA_ADDR]], align
+ // CHECK: store [10 x i32]* [[ARG3]], [10 x i32]** [[B_ADDR]], align
+ // CHECK: [[A:%.+]] = load i32*, i32** [[A_ADDR]], align
+ // CHECK: [[AA:%.+]] = load i16*, i16** [[AA_ADDR]], align
+ // CHECK: [[B:%.+]] = load [10 x i32]*, [10 x i32]** [[B_ADDR]], align
+ // CHECK: store i32 {{%.+}}, i32* [[A]], align
+ // CHECK: store i16 {{%.+}}, i16* [[AA]], align
+ // CHECK: [[ELT:%.+]] = getelementptr inbounds [10 x i32], [10 x i32]* [[B]],
+ // CHECK: store i32 {{%.+}}, i32* [[ELT]], align
+ // CHECK: ret void
+ // CHECK: }
+#endif
diff --git a/test/OpenMP/nvptx_target_parallel_proc_bind_codegen.cpp b/test/OpenMP/nvptx_target_parallel_proc_bind_codegen.cpp
new file mode 100644
index 000000000000..91c6de1b85d3
--- /dev/null
+++ b/test/OpenMP/nvptx_target_parallel_proc_bind_codegen.cpp
@@ -0,0 +1,106 @@
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -fexceptions -fcxx-exceptions -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// Check that the execution mode of all 3 target regions on the gpu is set to SPMD Mode.
+// CHECK-DAG: {{@__omp_offloading_.+l22}}_exec_mode = weak constant i8 0
+// CHECK-DAG: {{@__omp_offloading_.+l26}}_exec_mode = weak constant i8 0
+// CHECK-DAG: {{@__omp_offloading_.+l31}}_exec_mode = weak constant i8 0
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+ short aa = 0;
+ tx b[10];
+
+ #pragma omp target parallel proc_bind(master)
+ {
+ }
+
+ #pragma omp target parallel proc_bind(spread)
+ {
+ aa += 1;
+ }
+
+ #pragma omp target parallel proc_bind(close)
+ {
+ a += 1;
+ aa += 1;
+ b[2] += 1;
+ }
+
+ return a;
+}
+
+int bar(int n){
+ int a = 0;
+
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l22}}(
+ // CHECK: call void @__kmpc_spmd_kernel_init(
+ // CHECK: br label {{%?}}[[EXEC:.+]]
+ //
+ // CHECK: [[EXEC]]
+ // CHECK-NOT: call void @__kmpc_push_proc_bind
+ // CHECK: {{call|invoke}} void [[OP1:@.+]](i32* null, i32* null
+ // CHECK: br label {{%?}}[[DONE:.+]]
+ //
+ // CHECK: [[DONE]]
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+ // CHECK: }
+
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l26}}(
+ // CHECK: call void @__kmpc_spmd_kernel_init(
+ // CHECK: br label {{%?}}[[EXEC:.+]]
+ //
+ // CHECK: [[EXEC]]
+ // CHECK-NOT: call void @__kmpc_push_proc_bind
+ // CHECK: {{call|invoke}} void [[OP1:@.+]](i32* null, i32* null
+ // CHECK: br label {{%?}}[[DONE:.+]]
+ //
+ // CHECK: [[DONE]]
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+ // CHECK: }
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l31}}(
+ // CHECK: call void @__kmpc_spmd_kernel_init(
+ // CHECK: br label {{%?}}[[EXEC:.+]]
+ //
+ // CHECK: [[EXEC]]
+ // CHECK-NOT: call void @__kmpc_push_proc_bind
+ // CHECK: {{call|invoke}} void [[OP1:@.+]](i32* null, i32* null
+ // CHECK: br label {{%?}}[[DONE:.+]]
+ //
+ // CHECK: [[DONE]]
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+ // CHECK: }
+#endif
diff --git a/test/OpenMP/nvptx_target_parallel_reduction_codegen.cpp b/test/OpenMP/nvptx_target_parallel_reduction_codegen.cpp
new file mode 100644
index 000000000000..c4c3e977b0e2
--- /dev/null
+++ b/test/OpenMP/nvptx_target_parallel_reduction_codegen.cpp
@@ -0,0 +1,830 @@
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -verify -fopenmp -fexceptions -fcxx-exceptions -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// Check for the data transfer medium in shared memory to transfer the reduction list to the first warp.
+// CHECK-DAG: [[TRANSFER_STORAGE:@.+]] = common addrspace([[SHARED_ADDRSPACE:[0-9]+]]) global [32 x i64]
+
+// Check that the execution mode of all 3 target regions is set to Spmd Mode.
+// CHECK-DAG: {{@__omp_offloading_.+l27}}_exec_mode = weak constant i8 0
+// CHECK-DAG: {{@__omp_offloading_.+l32}}_exec_mode = weak constant i8 0
+// CHECK-DAG: {{@__omp_offloading_.+l38}}_exec_mode = weak constant i8 0
+
+template<typename tx>
+tx ftemplate(int n) {
+ int a;
+ short b;
+ tx c;
+ float d;
+ double e;
+
+ #pragma omp target parallel reduction(+: e) map(tofrom: e)
+ {
+ e += 5;
+ }
+
+ #pragma omp target parallel reduction(^: c) reduction(*: d) map(tofrom: c,d)
+ {
+ c ^= 2;
+ d *= 33;
+ }
+
+ #pragma omp target parallel reduction(|: a) reduction(max: b) map(tofrom: a,b)
+ {
+ a |= 1;
+ b = 99 > b ? 99 : b;
+ }
+
+ return a+b+c+d+e;
+}
+
+int bar(int n){
+ int a = 0;
+
+ a += ftemplate<char>(n);
+
+ return a;
+}
+
+ // CHECK: define {{.*}}void {{@__omp_offloading_.+template.+l27}}(
+ //
+ // CHECK: call void @__kmpc_spmd_kernel_init(
+ // CHECK: br label {{%?}}[[EXECUTE:.+]]
+ //
+ // CHECK: [[EXECUTE]]
+ // CHECK: {{call|invoke}} void [[PFN:@.+]](i32*
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ //
+ //
+ // define internal void [[PFN]](
+ // CHECK: store double {{[0\.e\+]+}}, double* [[E:%.+]], align
+ // CHECK: [[EV:%.+]] = load double, double* [[E]], align
+ // CHECK: [[ADD:%.+]] = fadd double [[EV]], 5
+ // CHECK: store double [[ADD]], double* [[E]], align
+ // CHECK: [[PTR1:%.+]] = getelementptr inbounds [[RLT:.+]], [1 x i8*]* [[RL:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[E_CAST:%.+]] = bitcast double* [[E]] to i8*
+ // CHECK: store i8* [[E_CAST]], i8** [[PTR1]], align
+ // CHECK: [[ARG_RL:%.+]] = bitcast [[RLT]]* [[RL]] to i8*
+ // CHECK: [[RET:%.+]] = call i32 @__kmpc_nvptx_parallel_reduce_nowait(i32 {{.+}}, i32 1, i{{32|64}} {{4|8}}, i8* [[ARG_RL]], void (i8*, i16, i16, i16)* [[SHUFFLE_REDUCE_FN:@.+]], void (i8*, i32)* [[WARP_COPY_FN:@.+]])
+ // CHECK: switch i32 [[RET]], label {{%?}}[[DEFAULTLABEL:.+]] [
+ // CHECK: i32 1, label {{%?}}[[REDLABEL:.+]]
+
+ // CHECK: [[REDLABEL]]
+ // CHECK: [[E_INV:%.+]] = load double, double* [[E_IN:%.+]], align
+ // CHECK: [[EV:%.+]] = load double, double* [[E]], align
+ // CHECK: [[ADD:%.+]] = fadd double [[E_INV]], [[EV]]
+ // CHECK: store double [[ADD]], double* [[E_IN]], align
+ // CHECK: call void @__kmpc_nvptx_end_reduce_nowait(
+ // CHECK: br label %[[DEFAULTLABEL]]
+ //
+ // CHECK: [[DEFAULTLABEL]]
+ // CHECK: ret
+
+ //
+ // Reduction function
+ // CHECK: define internal void [[REDUCTION_FUNC:@.+]](i8*, i8*)
+ // CHECK: [[VAR_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[VAR_RHS_VOID:%.+]] = load i8*, i8** [[VAR_RHS_REF]],
+ // CHECK: [[VAR_RHS:%.+]] = bitcast i8* [[VAR_RHS_VOID]] to double*
+ //
+ // CHECK: [[VAR_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[VAR_LHS_VOID:%.+]] = load i8*, i8** [[VAR_LHS_REF]],
+ // CHECK: [[VAR_LHS:%.+]] = bitcast i8* [[VAR_LHS_VOID]] to double*
+ //
+ // CHECK: [[VAR_LHS_VAL:%.+]] = load double, double* [[VAR_LHS]],
+ // CHECK: [[VAR_RHS_VAL:%.+]] = load double, double* [[VAR_RHS]],
+ // CHECK: [[RES:%.+]] = fadd double [[VAR_LHS_VAL]], [[VAR_RHS_VAL]]
+ // CHECK: store double [[RES]], double* [[VAR_LHS]],
+ // CHECK: ret void
+
+ //
+ // Shuffle and reduce function
+ // CHECK: define internal void [[SHUFFLE_REDUCE_FN]](i8*, i16 {{.*}}, i16 {{.*}}, i16 {{.*}})
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT:%.+]] = alloca double
+ //
+ // CHECK: [[LANEID:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[LANEOFFSET:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[ALGVER:%.+]] = load i16, i16* {{.+}}, align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: [[ELT_VAL:%.+]] = load double, double* [[ELT]], align
+ //
+ // CHECK: [[ELT_CAST:%.+]] = bitcast double [[ELT_VAL]] to i64
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT_VAL64:%.+]] = call i64 @__kmpc_shuffle_int64(i64 [[ELT_CAST]], i16 [[LANEOFFSET]], i16 [[WS]])
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = bitcast i64 [[REMOTE_ELT_VAL64]] to double
+ //
+ // CHECK: store double [[REMOTE_ELT_VAL]], double* [[REMOTE_ELT]], align
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = bitcast double* [[REMOTE_ELT]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT_VOID]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // Condition to reduce
+ // CHECK: [[CONDALG0:%.+]] = icmp eq i16 [[ALGVER]], 0
+ //
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp ult i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[CONDALG1:%.+]] = and i1 [[COND1]], [[COND2]]
+ //
+ // CHECK: [[COND3:%.+]] = icmp eq i16 [[ALGVER]], 2
+ // CHECK: [[COND4:%.+]] = and i16 [[LANEID]], 1
+ // CHECK: [[COND5:%.+]] = icmp eq i16 [[COND4]], 0
+ // CHECK: [[COND6:%.+]] = and i1 [[COND3]], [[COND5]]
+ // CHECK: [[COND7:%.+]] = icmp sgt i16 [[LANEOFFSET]], 0
+ // CHECK: [[CONDALG2:%.+]] = and i1 [[COND6]], [[COND7]]
+ //
+ // CHECK: [[COND8:%.+]] = or i1 [[CONDALG0]], [[CONDALG1]]
+ // CHECK: [[SHOULD_REDUCE:%.+]] = or i1 [[COND8]], [[CONDALG2]]
+ // CHECK: br i1 [[SHOULD_REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // Now check if we should just copy over the remote reduction list
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp uge i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[SHOULD_COPY:%.+]] = and i1 [[COND1]], [[COND2]]
+ // CHECK: br i1 [[SHOULD_COPY]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // CHECK: [[DO_COPY]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to double*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load double, double* [[REMOTE_ELT]], align
+ // CHECK: store double [[REMOTE_ELT_VAL]], double* [[ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // CHECK: [[COPY_CONT]]
+ // CHECK: void
+
+ //
+ // Inter warp copy function
+ // CHECK: define internal void [[WARP_COPY_FN]](i8*, i32)
+ // CHECK-DAG: [[LANEID:%.+]] = and i32 {{.+}}, 31
+ // CHECK-DAG: [[WARPID:%.+]] = ashr i32 {{.+}}, 5
+ // CHECK-DAG: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: [[ELT_VAL:%.+]] = load double, double* [[ELT]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to double addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store double [[ELT_VAL]], double addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to double addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load double, double addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: store double [[MEDIUM_ELT_VAL]], double* [[ELT]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: ret
+
+
+
+
+
+
+
+
+
+
+ // CHECK: define {{.*}}void {{@__omp_offloading_.+template.+l32}}(
+ //
+ // CHECK: call void @__kmpc_spmd_kernel_init(
+ // CHECK: br label {{%?}}[[EXECUTE:.+]]
+ //
+ // CHECK: [[EXECUTE]]
+ // CHECK: {{call|invoke}} void [[PFN1:@.+]](i32*
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ //
+ //
+ // define internal void [[PFN1]](
+ // CHECK: store float {{1\.[0e\+]+}}, float* [[D:%.+]], align
+ // CHECK: [[C_VAL:%.+]] = load i8, i8* [[C:%.+]], align
+ // CHECK: [[CONV:%.+]] = sext i8 [[C_VAL]] to i32
+ // CHECK: [[XOR:%.+]] = xor i32 [[CONV]], 2
+ // CHECK: [[TRUNC:%.+]] = trunc i32 [[XOR]] to i8
+ // CHECK: store i8 [[TRUNC]], i8* [[C]], align
+ // CHECK: [[DV:%.+]] = load float, float* [[D]], align
+ // CHECK: [[MUL:%.+]] = fmul float [[DV]], {{[0-9e\.\+]+}}
+ // CHECK: store float [[MUL]], float* [[D]], align
+ // CHECK: [[PTR1:%.+]] = getelementptr inbounds [[RLT:.+]], [2 x i8*]* [[RL:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: store i8* [[C]], i8** [[PTR1]], align
+ // CHECK: [[PTR2:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RL]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[D_CAST:%.+]] = bitcast float* [[D]] to i8*
+ // CHECK: store i8* [[D_CAST]], i8** [[PTR2]], align
+ // CHECK: [[ARG_RL:%.+]] = bitcast [[RLT]]* [[RL]] to i8*
+ // CHECK: [[RET:%.+]] = call i32 @__kmpc_nvptx_parallel_reduce_nowait(i32 {{.+}}, i32 2, i{{32|64}} {{8|16}}, i8* [[ARG_RL]], void (i8*, i16, i16, i16)* [[SHUFFLE_REDUCE_FN:@.+]], void (i8*, i32)* [[WARP_COPY_FN:@.+]])
+ // CHECK: switch i32 [[RET]], label {{%?}}[[DEFAULTLABEL:.+]] [
+ // CHECK: i32 1, label {{%?}}[[REDLABEL:.+]]
+
+ // CHECK: [[REDLABEL]]
+ // CHECK: [[C_INV8:%.+]] = load i8, i8* [[C_IN:%.+]], align
+ // CHECK: [[C_INV:%.+]] = sext i8 [[C_INV8]] to i32
+ // CHECK: [[CV8:%.+]] = load i8, i8* [[C]], align
+ // CHECK: [[CV:%.+]] = sext i8 [[CV8]] to i32
+ // CHECK: [[XOR:%.+]] = xor i32 [[C_INV]], [[CV]]
+ // CHECK: [[TRUNC:%.+]] = trunc i32 [[XOR]] to i8
+ // CHECK: store i8 [[TRUNC]], i8* [[C_IN]], align
+ // CHECK: [[D_INV:%.+]] = load float, float* [[D_IN:%.+]], align
+ // CHECK: [[DV:%.+]] = load float, float* [[D]], align
+ // CHECK: [[MUL:%.+]] = fmul float [[D_INV]], [[DV]]
+ // CHECK: store float [[MUL]], float* [[D_IN]], align
+ // CHECK: call void @__kmpc_nvptx_end_reduce_nowait(
+ // CHECK: br label %[[DEFAULTLABEL]]
+ //
+ // CHECK: [[DEFAULTLABEL]]
+ // CHECK: ret
+
+ //
+ // Reduction function
+ // CHECK: define internal void [[REDUCTION_FUNC:@.+]](i8*, i8*)
+ // CHECK: [[VAR1_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[VAR1_RHS:%.+]] = load i8*, i8** [[VAR1_RHS_REF]],
+ //
+ // CHECK: [[VAR1_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[VAR1_LHS:%.+]] = load i8*, i8** [[VAR1_LHS_REF]],
+ //
+ // CHECK: [[VAR2_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[VAR2_RHS_VOID:%.+]] = load i8*, i8** [[VAR2_RHS_REF]],
+ // CHECK: [[VAR2_RHS:%.+]] = bitcast i8* [[VAR2_RHS_VOID]] to float*
+ //
+ // CHECK: [[VAR2_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[VAR2_LHS_VOID:%.+]] = load i8*, i8** [[VAR2_LHS_REF]],
+ // CHECK: [[VAR2_LHS:%.+]] = bitcast i8* [[VAR2_LHS_VOID]] to float*
+ //
+ // CHECK: [[VAR1_LHS_VAL8:%.+]] = load i8, i8* [[VAR1_LHS]],
+ // CHECK: [[VAR1_LHS_VAL:%.+]] = sext i8 [[VAR1_LHS_VAL8]] to i32
+ // CHECK: [[VAR1_RHS_VAL8:%.+]] = load i8, i8* [[VAR1_RHS]],
+ // CHECK: [[VAR1_RHS_VAL:%.+]] = sext i8 [[VAR1_RHS_VAL8]] to i32
+ // CHECK: [[XOR:%.+]] = xor i32 [[VAR1_LHS_VAL]], [[VAR1_RHS_VAL]]
+ // CHECK: [[RES:%.+]] = trunc i32 [[XOR]] to i8
+ // CHECK: store i8 [[RES]], i8* [[VAR1_LHS]],
+ //
+ // CHECK: [[VAR2_LHS_VAL:%.+]] = load float, float* [[VAR2_LHS]],
+ // CHECK: [[VAR2_RHS_VAL:%.+]] = load float, float* [[VAR2_RHS]],
+ // CHECK: [[RES:%.+]] = fmul float [[VAR2_LHS_VAL]], [[VAR2_RHS_VAL]]
+ // CHECK: store float [[RES]], float* [[VAR2_LHS]],
+ // CHECK: ret void
+
+ //
+ // Shuffle and reduce function
+ // CHECK: define internal void [[SHUFFLE_REDUCE_FN]](i8*, i16 {{.*}}, i16 {{.*}}, i16 {{.*}})
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT1:%.+]] = alloca i8
+ // CHECK: [[REMOTE_ELT2:%.+]] = alloca float
+ //
+ // CHECK: [[LANEID:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[LANEOFFSET:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[ALGVER:%.+]] = load i16, i16* {{.+}}, align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VAL:%.+]] = load i8, i8* [[ELT_VOID]], align
+ //
+ // CHECK: [[ELT_CAST:%.+]] = sext i8 [[ELT_VAL]] to i32
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT1_VAL32:%.+]] = call i32 @__kmpc_shuffle_int32(i32 [[ELT_CAST]], i16 [[LANEOFFSET]], i16 [[WS]])
+ // CHECK: [[REMOTE_ELT1_VAL:%.+]] = trunc i32 [[REMOTE_ELT1_VAL32]] to i8
+ //
+ // CHECK: store i8 [[REMOTE_ELT1_VAL]], i8* [[REMOTE_ELT1]], align
+ // CHECK: store i8* [[REMOTE_ELT1]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: [[ELT_VAL:%.+]] = load float, float* [[ELT]], align
+ //
+ // CHECK: [[ELT_CAST:%.+]] = bitcast float [[ELT_VAL]] to i32
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT2_VAL32:%.+]] = call i32 @__kmpc_shuffle_int32(i32 [[ELT_CAST]], i16 [[LANEOFFSET]], i16 [[WS]])
+ // CHECK: [[REMOTE_ELT2_VAL:%.+]] = bitcast i32 [[REMOTE_ELT2_VAL32]] to float
+ //
+ // CHECK: store float [[REMOTE_ELT2_VAL]], float* [[REMOTE_ELT2]], align
+ // CHECK: [[REMOTE_ELT2C:%.+]] = bitcast float* [[REMOTE_ELT2]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT2C]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // Condition to reduce
+ // CHECK: [[CONDALG0:%.+]] = icmp eq i16 [[ALGVER]], 0
+ //
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp ult i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[CONDALG1:%.+]] = and i1 [[COND1]], [[COND2]]
+ //
+ // CHECK: [[COND3:%.+]] = icmp eq i16 [[ALGVER]], 2
+ // CHECK: [[COND4:%.+]] = and i16 [[LANEID]], 1
+ // CHECK: [[COND5:%.+]] = icmp eq i16 [[COND4]], 0
+ // CHECK: [[COND6:%.+]] = and i1 [[COND3]], [[COND5]]
+ // CHECK: [[COND7:%.+]] = icmp sgt i16 [[LANEOFFSET]], 0
+ // CHECK: [[CONDALG2:%.+]] = and i1 [[COND6]], [[COND7]]
+ //
+ // CHECK: [[COND8:%.+]] = or i1 [[CONDALG0]], [[CONDALG1]]
+ // CHECK: [[SHOULD_REDUCE:%.+]] = or i1 [[COND8]], [[CONDALG2]]
+ // CHECK: br i1 [[SHOULD_REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // Now check if we should just copy over the remote reduction list
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp uge i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[SHOULD_COPY:%.+]] = and i1 [[COND1]], [[COND2]]
+ // CHECK: br i1 [[SHOULD_COPY]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // CHECK: [[DO_COPY]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i8, i8* [[REMOTE_ELT_VOID]], align
+ // CHECK: store i8 [[REMOTE_ELT_VAL]], i8* [[ELT_VOID]], align
+ //
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to float*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load float, float* [[REMOTE_ELT]], align
+ // CHECK: store float [[REMOTE_ELT_VAL]], float* [[ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // CHECK: [[COPY_CONT]]
+ // CHECK: void
+
+ //
+ // Inter warp copy function
+ // CHECK: define internal void [[WARP_COPY_FN]](i8*, i32)
+ // CHECK-DAG: [[LANEID:%.+]] = and i32 {{.+}}, 31
+ // CHECK-DAG: [[WARPID:%.+]] = ashr i32 {{.+}}, 5
+ // CHECK-DAG: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT_VAL:%.+]] = load i8, i8* [[ELT_VOID]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i8 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store i8 [[ELT_VAL]], i8 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i8 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load i8, i8 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: store i8 [[MEDIUM_ELT_VAL]], i8* [[ELT_VOID]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: [[ELT_VAL:%.+]] = load float, float* [[ELT]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to float addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store float [[ELT_VAL]], float addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to float addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load float, float addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: store float [[MEDIUM_ELT_VAL]], float* [[ELT]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: ret
+
+
+
+
+
+
+
+
+
+
+ // CHECK: define {{.*}}void {{@__omp_offloading_.+template.+l38}}(
+ //
+ // CHECK: call void @__kmpc_spmd_kernel_init(
+ // CHECK: br label {{%?}}[[EXECUTE:.+]]
+ //
+ // CHECK: [[EXECUTE]]
+ // CHECK: {{call|invoke}} void [[PFN2:@.+]](i32*
+ // CHECK: call void @__kmpc_spmd_kernel_deinit()
+ //
+ //
+ // define internal void [[PFN2]](
+ // CHECK: store i32 0, i32* [[A:%.+]], align
+ // CHECK: store i16 -32768, i16* [[B:%.+]], align
+ // CHECK: [[A_VAL:%.+]] = load i32, i32* [[A:%.+]], align
+ // CHECK: [[OR:%.+]] = or i32 [[A_VAL]], 1
+ // CHECK: store i32 [[OR]], i32* [[A]], align
+ // CHECK: [[BV16:%.+]] = load i16, i16* [[B]], align
+ // CHECK: [[BV:%.+]] = sext i16 [[BV16]] to i32
+ // CHECK: [[CMP:%.+]] = icmp sgt i32 99, [[BV]]
+ // CHECK: br i1 [[CMP]], label {{%?}}[[DO_MAX:.+]], label {{%?}}[[MAX_ELSE:.+]]
+ //
+ // CHECK: [[DO_MAX]]
+ // CHECK: br label {{%?}}[[MAX_CONT:.+]]
+ //
+ // CHECK: [[MAX_ELSE]]
+ // CHECK: [[BV:%.+]] = load i16, i16* [[B]], align
+ // CHECK: [[MAX:%.+]] = sext i16 [[BV]] to i32
+ // CHECK: br label {{%?}}[[MAX_CONT]]
+ //
+ // CHECK: [[MAX_CONT]]
+ // CHECK: [[B_LVALUE:%.+]] = phi i32 [ 99, %[[DO_MAX]] ], [ [[MAX]], %[[MAX_ELSE]] ]
+ // CHECK: [[TRUNC:%.+]] = trunc i32 [[B_LVALUE]] to i16
+ // CHECK: store i16 [[TRUNC]], i16* [[B]], align
+ // CHECK: [[PTR1:%.+]] = getelementptr inbounds [[RLT:.+]], [2 x i8*]* [[RL:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[A_CAST:%.+]] = bitcast i32* [[A]] to i8*
+ // CHECK: store i8* [[A_CAST]], i8** [[PTR1]], align
+ // CHECK: [[PTR2:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RL]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[B_CAST:%.+]] = bitcast i16* [[B]] to i8*
+ // CHECK: store i8* [[B_CAST]], i8** [[PTR2]], align
+ // CHECK: [[ARG_RL:%.+]] = bitcast [[RLT]]* [[RL]] to i8*
+ // CHECK: [[RET:%.+]] = call i32 @__kmpc_nvptx_parallel_reduce_nowait(i32 {{.+}}, i32 2, i{{32|64}} {{8|16}}, i8* [[ARG_RL]], void (i8*, i16, i16, i16)* [[SHUFFLE_REDUCE_FN:@.+]], void (i8*, i32)* [[WARP_COPY_FN:@.+]])
+ // CHECK: switch i32 [[RET]], label {{%?}}[[DEFAULTLABEL:.+]] [
+ // CHECK: i32 1, label {{%?}}[[REDLABEL:.+]]
+
+ // CHECK: [[REDLABEL]]
+ // CHECK: [[A_INV:%.+]] = load i32, i32* [[A_IN:%.+]], align
+ // CHECK: [[AV:%.+]] = load i32, i32* [[A]], align
+ // CHECK: [[OR:%.+]] = or i32 [[A_INV]], [[AV]]
+ // CHECK: store i32 [[OR]], i32* [[A_IN]], align
+ // CHECK: [[B_INV16:%.+]] = load i16, i16* [[B_IN:%.+]], align
+ // CHECK: [[B_INV:%.+]] = sext i16 [[B_INV16]] to i32
+ // CHECK: [[BV16:%.+]] = load i16, i16* [[B]], align
+ // CHECK: [[BV:%.+]] = sext i16 [[BV16]] to i32
+ // CHECK: [[CMP:%.+]] = icmp sgt i32 [[B_INV]], [[BV]]
+ // CHECK: br i1 [[CMP]], label {{%?}}[[DO_MAX:.+]], label {{%?}}[[MAX_ELSE:.+]]
+ //
+ // CHECK: [[DO_MAX]]
+ // CHECK: [[MAX1:%.+]] = load i16, i16* [[B_IN]], align
+ // CHECK: br label {{%?}}[[MAX_CONT:.+]]
+ //
+ // CHECK: [[MAX_ELSE]]
+ // CHECK: [[MAX2:%.+]] = load i16, i16* [[B]], align
+ // CHECK: br label {{%?}}[[MAX_CONT]]
+ //
+ // CHECK: [[MAX_CONT]]
+ // CHECK: [[B_MAX:%.+]] = phi i16 [ [[MAX1]], %[[DO_MAX]] ], [ [[MAX2]], %[[MAX_ELSE]] ]
+ // CHECK: store i16 [[B_MAX]], i16* [[B_IN]], align
+ // CHECK: call void @__kmpc_nvptx_end_reduce_nowait(
+ // CHECK: br label %[[DEFAULTLABEL]]
+ //
+ // CHECK: [[DEFAULTLABEL]]
+ // CHECK: ret
+
+ //
+ // Reduction function
+ // CHECK: define internal void [[REDUCTION_FUNC:@.+]](i8*, i8*)
+ // CHECK: [[VAR1_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[VAR1_RHS_VOID:%.+]] = load i8*, i8** [[VAR1_RHS_REF]],
+ // CHECK: [[VAR1_RHS:%.+]] = bitcast i8* [[VAR1_RHS_VOID]] to i32*
+ //
+ // CHECK: [[VAR1_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[VAR1_LHS_VOID:%.+]] = load i8*, i8** [[VAR1_LHS_REF]],
+ // CHECK: [[VAR1_LHS:%.+]] = bitcast i8* [[VAR1_LHS_VOID]] to i32*
+ //
+ // CHECK: [[VAR2_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[VAR2_RHS_VOID:%.+]] = load i8*, i8** [[VAR2_RHS_REF]],
+ // CHECK: [[VAR2_RHS:%.+]] = bitcast i8* [[VAR2_RHS_VOID]] to i16*
+ //
+ // CHECK: [[VAR2_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[VAR2_LHS_VOID:%.+]] = load i8*, i8** [[VAR2_LHS_REF]],
+ // CHECK: [[VAR2_LHS:%.+]] = bitcast i8* [[VAR2_LHS_VOID]] to i16*
+ //
+ // CHECK: [[VAR1_LHS_VAL:%.+]] = load i32, i32* [[VAR1_LHS]],
+ // CHECK: [[VAR1_RHS_VAL:%.+]] = load i32, i32* [[VAR1_RHS]],
+ // CHECK: [[OR:%.+]] = or i32 [[VAR1_LHS_VAL]], [[VAR1_RHS_VAL]]
+ // CHECK: store i32 [[OR]], i32* [[VAR1_LHS]],
+ //
+ // CHECK: [[VAR2_LHS_VAL16:%.+]] = load i16, i16* [[VAR2_LHS]],
+ // CHECK: [[VAR2_LHS_VAL:%.+]] = sext i16 [[VAR2_LHS_VAL16]] to i32
+ // CHECK: [[VAR2_RHS_VAL16:%.+]] = load i16, i16* [[VAR2_RHS]],
+ // CHECK: [[VAR2_RHS_VAL:%.+]] = sext i16 [[VAR2_RHS_VAL16]] to i32
+ //
+ // CHECK: [[CMP:%.+]] = icmp sgt i32 [[VAR2_LHS_VAL]], [[VAR2_RHS_VAL]]
+ // CHECK: br i1 [[CMP]], label {{%?}}[[DO_MAX:.+]], label {{%?}}[[MAX_ELSE:.+]]
+ //
+ // CHECK: [[DO_MAX]]
+ // CHECK: [[MAX1:%.+]] = load i16, i16* [[VAR2_LHS]], align
+ // CHECK: br label {{%?}}[[MAX_CONT:.+]]
+ //
+ // CHECK: [[MAX_ELSE]]
+ // CHECK: [[MAX2:%.+]] = load i16, i16* [[VAR2_RHS]], align
+ // CHECK: br label {{%?}}[[MAX_CONT]]
+ //
+ // CHECK: [[MAX_CONT]]
+ // CHECK: [[MAXV:%.+]] = phi i16 [ [[MAX1]], %[[DO_MAX]] ], [ [[MAX2]], %[[MAX_ELSE]] ]
+ // CHECK: store i16 [[MAXV]], i16* [[VAR2_LHS]],
+ // CHECK: ret void
+
+ //
+ // Shuffle and reduce function
+ // CHECK: define internal void [[SHUFFLE_REDUCE_FN]](i8*, i16 {{.*}}, i16 {{.*}}, i16 {{.*}})
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT1:%.+]] = alloca i32
+ // CHECK: [[REMOTE_ELT2:%.+]] = alloca i16
+ //
+ // CHECK: [[LANEID:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[LANEOFFSET:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[ALGVER:%.+]] = load i16, i16* {{.+}}, align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: [[ELT_VAL:%.+]] = load i32, i32* [[ELT]], align
+ //
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT1_VAL:%.+]] = call i32 @__kmpc_shuffle_int32(i32 [[ELT_VAL]], i16 [[LANEOFFSET]], i16 [[WS]])
+ //
+ // CHECK: store i32 [[REMOTE_ELT1_VAL]], i32* [[REMOTE_ELT1]], align
+ // CHECK: [[REMOTE_ELT1C:%.+]] = bitcast i32* [[REMOTE_ELT1]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT1C]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: [[ELT_VAL:%.+]] = load i16, i16* [[ELT]], align
+ //
+ // CHECK: [[ELT_CAST:%.+]] = sext i16 [[ELT_VAL]] to i32
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT2_VAL32:%.+]] = call i32 @__kmpc_shuffle_int32(i32 [[ELT_CAST]], i16 [[LANEOFFSET]], i16 [[WS]])
+ // CHECK: [[REMOTE_ELT2_VAL:%.+]] = trunc i32 [[REMOTE_ELT2_VAL32]] to i16
+ //
+ // CHECK: store i16 [[REMOTE_ELT2_VAL]], i16* [[REMOTE_ELT2]], align
+ // CHECK: [[REMOTE_ELT2C:%.+]] = bitcast i16* [[REMOTE_ELT2]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT2C]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // Condition to reduce
+ // CHECK: [[CONDALG0:%.+]] = icmp eq i16 [[ALGVER]], 0
+ //
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp ult i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[CONDALG1:%.+]] = and i1 [[COND1]], [[COND2]]
+ //
+ // CHECK: [[COND3:%.+]] = icmp eq i16 [[ALGVER]], 2
+ // CHECK: [[COND4:%.+]] = and i16 [[LANEID]], 1
+ // CHECK: [[COND5:%.+]] = icmp eq i16 [[COND4]], 0
+ // CHECK: [[COND6:%.+]] = and i1 [[COND3]], [[COND5]]
+ // CHECK: [[COND7:%.+]] = icmp sgt i16 [[LANEOFFSET]], 0
+ // CHECK: [[CONDALG2:%.+]] = and i1 [[COND6]], [[COND7]]
+ //
+ // CHECK: [[COND8:%.+]] = or i1 [[CONDALG0]], [[CONDALG1]]
+ // CHECK: [[SHOULD_REDUCE:%.+]] = or i1 [[COND8]], [[CONDALG2]]
+ // CHECK: br i1 [[SHOULD_REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // Now check if we should just copy over the remote reduction list
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp uge i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[SHOULD_COPY:%.+]] = and i1 [[COND1]], [[COND2]]
+ // CHECK: br i1 [[SHOULD_COPY]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // CHECK: [[DO_COPY]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to i32*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i32, i32* [[REMOTE_ELT]], align
+ // CHECK: store i32 [[REMOTE_ELT_VAL]], i32* [[ELT]], align
+ //
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to i16*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i16, i16* [[REMOTE_ELT]], align
+ // CHECK: store i16 [[REMOTE_ELT_VAL]], i16* [[ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // CHECK: [[COPY_CONT]]
+ // CHECK: void
+
+ //
+ // Inter warp copy function
+ // CHECK: define internal void [[WARP_COPY_FN]](i8*, i32)
+ // CHECK-DAG: [[LANEID:%.+]] = and i32 {{.+}}, 31
+ // CHECK-DAG: [[WARPID:%.+]] = ashr i32 {{.+}}, 5
+ // CHECK-DAG: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: [[ELT_VAL:%.+]] = load i32, i32* [[ELT]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i32 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store i32 [[ELT_VAL]], i32 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i32 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load i32, i32 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: store i32 [[MEDIUM_ELT_VAL]], i32* [[ELT]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: [[ELT_VAL:%.+]] = load i16, i16* [[ELT]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i16 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store i16 [[ELT_VAL]], i16 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i16 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load i16, i16 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i{{32|64}} 0, i{{32|64}} 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: store i16 [[MEDIUM_ELT_VAL]], i16* [[ELT]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: ret
+
+#endif
diff --git a/test/OpenMP/nvptx_target_printf_codegen.c b/test/OpenMP/nvptx_target_printf_codegen.c
new file mode 100644
index 000000000000..0de6885a5a72
--- /dev/null
+++ b/test/OpenMP/nvptx_target_printf_codegen.c
@@ -0,0 +1,116 @@
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple i386-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+
+#include <stdarg.h>
+
+// expected-no-diagnostics
+extern int printf(const char *, ...);
+extern int vprintf(const char *, va_list);
+
+// Check a simple call to printf end-to-end.
+// CHECK: [[SIMPLE_PRINTF_TY:%[a-zA-Z0-9_]+]] = type { i32, i64, double }
+int CheckSimple() {
+ // CHECK: define {{.*}}void [[T1:@__omp_offloading_.+CheckSimple.+]]_worker()
+#pragma omp target
+ {
+ // Entry point.
+ // CHECK: define {{.*}}void [[T1]]()
+ // Alloca in entry block.
+ // CHECK: [[BUF:%[a-zA-Z0-9_]+]] = alloca [[SIMPLE_PRINTF_TY]]
+
+ // CHECK: {{call|invoke}} void [[T1]]_worker()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK-DAG: [[CMTID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+ // CHECK-DAG: [[CMNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[CMWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[IS_MASTER:%.+]] = icmp eq i32 [[CMTID]],
+ // CHECK: br i1 [[IS_MASTER]], label {{%?}}[[MASTER:.+]], label {{%?}}[[EXIT]]
+ //
+ // CHECK: [[MASTER]]
+ // CHECK-DAG: [[MNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[MWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[MTMP1:%.+]] = sub i32 [[MNTH]], [[MWS]]
+ // CHECK: call void @__kmpc_kernel_init(i32 [[MTMP1]]
+
+ // printf in master-only basic block.
+ // CHECK: [[FMT:%[0-9]+]] = load{{.*}}%fmt
+ const char* fmt = "%d %lld %f";
+ // CHECK: [[PTR0:%[0-9]+]] = getelementptr inbounds [[SIMPLE_PRINTF_TY]], [[SIMPLE_PRINTF_TY]]* [[BUF]], i32 0, i32 0
+ // CHECK: store i32 1, i32* [[PTR0]], align 4
+ // CHECK: [[PTR1:%[0-9]+]] = getelementptr inbounds [[SIMPLE_PRINTF_TY]], [[SIMPLE_PRINTF_TY]]* [[BUF]], i32 0, i32 1
+ // CHECK: store i64 2, i64* [[PTR1]], align 8
+ // CHECK: [[PTR2:%[0-9]+]] = getelementptr inbounds [[SIMPLE_PRINTF_TY]], [[SIMPLE_PRINTF_TY]]* [[BUF]], i32 0, i32 2
+
+ // CHECK: store double 3.0{{[^,]*}}, double* [[PTR2]], align 8
+ // CHECK: [[BUF_CAST:%[0-9]+]] = bitcast [[SIMPLE_PRINTF_TY]]* [[BUF]] to i8*
+ // CHECK: [[RET:%[0-9]+]] = call i32 @vprintf(i8* [[FMT]], i8* [[BUF_CAST]])
+ printf(fmt, 1, 2ll, 3.0);
+ }
+
+ return 0;
+}
+
+void CheckNoArgs() {
+ // CHECK: define {{.*}}void [[T2:@__omp_offloading_.+CheckNoArgs.+]]_worker()
+#pragma omp target
+ {
+ // Entry point.
+ // CHECK: define {{.*}}void [[T2]]()
+
+ // CHECK: {{call|invoke}} void [[T2]]_worker()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK-DAG: [[CMTID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+ // CHECK-DAG: [[CMNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[CMWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[IS_MASTER:%.+]] = icmp eq i32 [[CMTID]],
+ // CHECK: br i1 [[IS_MASTER]], label {{%?}}[[MASTER:.+]], label {{%?}}[[EXIT]]
+ //
+ // CHECK: [[MASTER]]
+ // CHECK-DAG: [[MNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[MWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[MTMP1:%.+]] = sub i32 [[MNTH]], [[MWS]]
+ // CHECK: call void @__kmpc_kernel_init(i32 [[MTMP1]]
+
+ // printf in master-only basic block.
+ // CHECK: call i32 @vprintf({{.*}}, i8* null){{$}}
+ printf("hello, world!");
+ }
+}
+
+// Check that printf's alloca happens in the entry block, not inside the if
+// statement.
+int foo;
+void CheckAllocaIsInEntryBlock() {
+ // CHECK: define {{.*}}void [[T3:@__omp_offloading_.+CheckAllocaIsInEntryBlock.+]]_worker()
+#pragma omp target
+ {
+ // Entry point.
+ // CHECK: define {{.*}}void [[T3]](
+ // Alloca in entry block.
+ // CHECK: alloca %printf_args
+
+ // CHECK: {{call|invoke}} void [[T3]]_worker()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK-DAG: [[CMTID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+ // CHECK-DAG: [[CMNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[CMWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[IS_MASTER:%.+]] = icmp eq i32 [[CMTID]],
+ // CHECK: br i1 [[IS_MASTER]], label {{%?}}[[MASTER:.+]], label {{%?}}[[EXIT]]
+ //
+ // CHECK: [[MASTER]]
+ // CHECK-DAG: [[MNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[MWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[MTMP1:%.+]] = sub i32 [[MNTH]], [[MWS]]
+ // CHECK: call void @__kmpc_kernel_init(i32 [[MTMP1]]
+
+ if (foo) {
+ printf("%d", 42);
+ }
+ }
+}
diff --git a/test/OpenMP/nvptx_target_teams_codegen.cpp b/test/OpenMP/nvptx_target_teams_codegen.cpp
new file mode 100644
index 000000000000..e823eabbb10f
--- /dev/null
+++ b/test/OpenMP/nvptx_target_teams_codegen.cpp
@@ -0,0 +1,222 @@
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -verify -fopenmp -fexceptions -fcxx-exceptions -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// Check that the execution mode of all 2 target regions is set to Generic Mode.
+// CHECK-DAG: {{@__omp_offloading_.+l26}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l31}}_exec_mode = weak constant i8 1
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+ short aa = 0;
+ tx b[10];
+
+ #pragma omp target teams if(0)
+ {
+ b[2] += 1;
+ }
+
+ #pragma omp target teams if(1)
+ {
+ a = '1';
+ }
+
+ #pragma omp target teams if(n>40)
+ {
+ aa = 1;
+ }
+
+ return a;
+}
+
+int bar(int n){
+ int a = 0;
+
+ a += ftemplate<char>(n);
+
+ return a;
+}
+
+ // CHECK-NOT: define {{.*}}void {{@__omp_offloading_.+template.+l21}}_worker()
+
+
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l26}}_worker()
+ // CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
+ // CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
+ // CHECK: store i8* null, i8** [[OMP_WORK_FN]],
+ // CHECK: store i8 0, i8* [[OMP_EXEC_STATUS]],
+ // CHECK: br label {{%?}}[[AWAIT_WORK:.+]]
+ //
+ // CHECK: [[AWAIT_WORK]]
+ // CHECK: call void @llvm.nvvm.barrier0()
+ // CHECK: [[KPR:%.+]] = call i1 @__kmpc_kernel_parallel(i8** [[OMP_WORK_FN]])
+ // CHECK: [[KPRB:%.+]] = zext i1 [[KPR]] to i8
+ // store i8 [[KPRB]], i8* [[OMP_EXEC_STATUS]], align 1
+ // CHECK: [[WORK:%.+]] = load i8*, i8** [[OMP_WORK_FN]],
+ // CHECK: [[SHOULD_EXIT:%.+]] = icmp eq i8* [[WORK]], null
+ // CHECK: br i1 [[SHOULD_EXIT]], label {{%?}}[[EXIT:.+]], label {{%?}}[[SEL_WORKERS:.+]]
+ //
+ // CHECK: [[SEL_WORKERS]]
+ // CHECK: [[ST:%.+]] = load i8, i8* [[OMP_EXEC_STATUS]]
+ // CHECK: [[IS_ACTIVE:%.+]] = icmp ne i8 [[ST]], 0
+ // CHECK: br i1 [[IS_ACTIVE]], label {{%?}}[[EXEC_PARALLEL:.+]], label {{%?}}[[BAR_PARALLEL:.+]]
+ //
+ // CHECK: [[EXEC_PARALLEL]]
+ // CHECK: br label {{%?}}[[TERM_PARALLEL:.+]]
+ //
+ // CHECK: [[TERM_PARALLEL]]
+ // CHECK: call void @__kmpc_kernel_end_parallel()
+ // CHECK: br label {{%?}}[[BAR_PARALLEL]]
+ //
+ // CHECK: [[BAR_PARALLEL]]
+ // CHECK: call void @llvm.nvvm.barrier0()
+ // CHECK: br label {{%?}}[[AWAIT_WORK]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+
+ // CHECK: define {{.*}}void [[T1:@__omp_offloading_.+template.+l26]](i[[SZ:32|64]] [[A:%[^)]+]])
+ // CHECK: store i[[SZ]] [[A]], i[[SZ]]* [[A_ADDR:%.+]], align
+ // CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[A_ADDR]] to i8*
+
+ // CHECK-DAG: [[TID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+ // CHECK-DAG: [[NTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK-DAG: [[TH_LIMIT:%.+]] = sub i32 [[NTH]], [[WS]]
+ // CHECK: [[IS_WORKER:%.+]] = icmp ult i32 [[TID]], [[TH_LIMIT]]
+ // CHECK: br i1 [[IS_WORKER]], label {{%?}}[[WORKER:.+]], label {{%?}}[[CHECK_MASTER:.+]]
+ //
+ // CHECK: [[WORKER]]
+ // CHECK: {{call|invoke}} void [[T1]]_worker()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[CHECK_MASTER]]
+ // CHECK-DAG: [[CMTID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+ // CHECK-DAG: [[CMNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[CMWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[IS_MASTER:%.+]] = icmp eq i32 [[CMTID]],
+ // CHECK: br i1 [[IS_MASTER]], label {{%?}}[[MASTER:.+]], label {{%?}}[[EXIT]]
+ //
+ // CHECK: [[MASTER]]
+ // CHECK-DAG: [[MNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[MWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[MTMP1:%.+]] = sub i32 [[MNTH]], [[MWS]]
+ // CHECK: call void @__kmpc_kernel_init(i32 [[MTMP1]]
+ //
+ // CHECK-NOT: kmpc_fork_teams
+ // CHECK: [[A_VAL:%.+]] = load i8, i8* [[CONV]], align
+ // CHECK: [[ACP:%.+]] = bitcast i[[SZ]]* [[AC:%.+]] to i8*
+ // CHECK: store i8 [[A_VAL]], i8* [[ACP]], align
+ // CHECK: [[ACV:%.+]] = load i[[SZ]], i[[SZ]]* [[AC]], align
+ // CHECK: store i[[SZ]] [[ACV]], i[[SZ]]* [[A_ADDR_T:%.+]], align
+ // CHECK: [[CONV2:%.+]] = bitcast i[[SZ]]* [[A_ADDR_T]] to i8*
+ // CHECK: store i8 49, i8* [[CONV2]], align
+ // CHECK: br label {{%?}}[[TERMINATE:.+]]
+ //
+ // CHECK: [[TERMINATE]]
+ // CHECK: call void @__kmpc_kernel_deinit()
+ // CHECK: call void @llvm.nvvm.barrier0()
+ // CHECK: br label {{%?}}[[EXIT]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+
+
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l31}}_worker()
+ // CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
+ // CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
+ // CHECK: store i8* null, i8** [[OMP_WORK_FN]],
+ // CHECK: store i8 0, i8* [[OMP_EXEC_STATUS]],
+ // CHECK: br label {{%?}}[[AWAIT_WORK:.+]]
+ //
+ // CHECK: [[AWAIT_WORK]]
+ // CHECK: call void @llvm.nvvm.barrier0()
+ // CHECK: [[KPR:%.+]] = call i1 @__kmpc_kernel_parallel(i8** [[OMP_WORK_FN]])
+ // CHECK: [[KPRB:%.+]] = zext i1 [[KPR]] to i8
+ // store i8 [[KPRB]], i8* [[OMP_EXEC_STATUS]], align 1
+ // CHECK: [[WORK:%.+]] = load i8*, i8** [[OMP_WORK_FN]],
+ // CHECK: [[SHOULD_EXIT:%.+]] = icmp eq i8* [[WORK]], null
+ // CHECK: br i1 [[SHOULD_EXIT]], label {{%?}}[[EXIT:.+]], label {{%?}}[[SEL_WORKERS:.+]]
+ //
+ // CHECK: [[SEL_WORKERS]]
+ // CHECK: [[ST:%.+]] = load i8, i8* [[OMP_EXEC_STATUS]]
+ // CHECK: [[IS_ACTIVE:%.+]] = icmp ne i8 [[ST]], 0
+ // CHECK: br i1 [[IS_ACTIVE]], label {{%?}}[[EXEC_PARALLEL:.+]], label {{%?}}[[BAR_PARALLEL:.+]]
+ //
+ // CHECK: [[EXEC_PARALLEL]]
+ // CHECK: br label {{%?}}[[TERM_PARALLEL:.+]]
+ //
+ // CHECK: [[TERM_PARALLEL]]
+ // CHECK: call void @__kmpc_kernel_end_parallel()
+ // CHECK: br label {{%?}}[[BAR_PARALLEL]]
+ //
+ // CHECK: [[BAR_PARALLEL]]
+ // CHECK: call void @llvm.nvvm.barrier0()
+ // CHECK: br label {{%?}}[[AWAIT_WORK]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+
+ // CHECK: define {{.*}}void [[T2:@__omp_offloading_.+template.+l31]](i[[SZ:32|64]] [[AA:%[^)]+]])
+ // CHECK: store i[[SZ]] [[AA]], i[[SZ]]* [[AA_ADDR:%.+]], align
+ // CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+
+ // CHECK-DAG: [[TID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+ // CHECK-DAG: [[NTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK-DAG: [[TH_LIMIT:%.+]] = sub i32 [[NTH]], [[WS]]
+ // CHECK: [[IS_WORKER:%.+]] = icmp ult i32 [[TID]], [[TH_LIMIT]]
+ // CHECK: br i1 [[IS_WORKER]], label {{%?}}[[WORKER:.+]], label {{%?}}[[CHECK_MASTER:.+]]
+ //
+ // CHECK: [[WORKER]]
+ // CHECK: {{call|invoke}} void [[T2]]_worker()
+ // CHECK: br label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[CHECK_MASTER]]
+ // CHECK-DAG: [[CMTID:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+ // CHECK-DAG: [[CMNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[CMWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[IS_MASTER:%.+]] = icmp eq i32 [[CMTID]],
+ // CHECK: br i1 [[IS_MASTER]], label {{%?}}[[MASTER:.+]], label {{%?}}[[EXIT]]
+ //
+ // CHECK: [[MASTER]]
+ // CHECK-DAG: [[MNTH:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.ntid.x()
+ // CHECK-DAG: [[MWS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[MTMP1:%.+]] = sub i32 [[MNTH]], [[MWS]]
+ // CHECK: call void @__kmpc_kernel_init(i32 [[MTMP1]]
+ //
+ // CHECK-NOT: kmpc_fork_teams
+ // CHECK: [[AA_VAL:%.+]] = load i16, i16* [[CONV]], align
+ // CHECK: [[ACP:%.+]] = bitcast i[[SZ]]* [[AC:%.+]] to i16*
+ // CHECK: store i16 [[AA_VAL]], i16* [[ACP]], align
+ // CHECK: [[ACV:%.+]] = load i[[SZ]], i[[SZ]]* [[AC]], align
+ // CHECK: store i[[SZ]] [[ACV]], i[[SZ]]* [[AA_ADDR_T:%.+]], align
+ // CHECK: [[CONV2:%.+]] = bitcast i[[SZ]]* [[AA_ADDR_T]] to i16*
+ // CHECK: store i16 1, i16* [[CONV2]], align
+ // CHECK: br label {{%?}}[[TERMINATE:.+]]
+ //
+ // CHECK: [[TERMINATE]]
+ // CHECK: call void @__kmpc_kernel_deinit()
+ // CHECK: call void @llvm.nvvm.barrier0()
+ // CHECK: br label {{%?}}[[EXIT]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: ret void
+
+
+#endif
diff --git a/test/OpenMP/nvptx_teams_reduction_codegen.cpp b/test/OpenMP/nvptx_teams_reduction_codegen.cpp
new file mode 100644
index 000000000000..ae129ebfae4d
--- /dev/null
+++ b/test/OpenMP/nvptx_teams_reduction_codegen.cpp
@@ -0,0 +1,1143 @@
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -verify -fopenmp -fexceptions -fcxx-exceptions -x c++ -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// Check for the data transfer medium in shared memory to transfer the reduction list to the first warp.
+// CHECK-DAG: [[TRANSFER_STORAGE:@.+]] = common addrspace([[SHARED_ADDRSPACE:[0-9]+]]) global [32 x i64]
+
+// Check that the execution mode of all 3 target regions is set to Generic Mode.
+// CHECK-DAG: {{@__omp_offloading_.+l27}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l33}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l40}}_exec_mode = weak constant i8 1
+
+template<typename tx>
+tx ftemplate(int n) {
+ int a;
+ short b;
+ tx c;
+ float d;
+ double e;
+
+ #pragma omp target
+ #pragma omp teams reduction(+: e)
+ {
+ e += 5;
+ }
+
+ #pragma omp target
+ #pragma omp teams reduction(^: c) reduction(*: d)
+ {
+ c ^= 2;
+ d *= 33;
+ }
+
+ #pragma omp target
+ #pragma omp teams reduction(|: a) reduction(max: b)
+ {
+ a |= 1;
+ b = 99 > b ? 99 : b;
+ }
+
+ return a+b+c+d+e;
+}
+
+int bar(int n){
+ int a = 0;
+
+ a += ftemplate<char>(n);
+
+ return a;
+}
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l27}}_worker()
+
+ // CHECK: define {{.*}}void [[T1:@__omp_offloading_.+template.+l27]](
+ //
+ // CHECK: {{call|invoke}} void [[T1]]_worker()
+ //
+ // CHECK: call void @__kmpc_kernel_init(
+ //
+ // CHECK: store double {{[0\.e\+]+}}, double* [[E:%.+]], align
+ // CHECK: [[EV:%.+]] = load double, double* [[E]], align
+ // CHECK: [[ADD:%.+]] = fadd double [[EV]], 5
+ // CHECK: store double [[ADD]], double* [[E]], align
+ // CHECK: [[PTR1:%.+]] = getelementptr inbounds [[RLT:.+]], [1 x i8*]* [[RL:%.+]], i[[SZ:32|64]] 0, i{{32|64}} 0
+ // CHECK: [[E_CAST:%.+]] = bitcast double* [[E]] to i8*
+ // CHECK: store i8* [[E_CAST]], i8** [[PTR1]], align
+ // CHECK: [[ARG_RL:%.+]] = bitcast [[RLT]]* [[RL]] to i8*
+ // CHECK: [[RET:%.+]] = call i32 @__kmpc_nvptx_teams_reduce_nowait(i32 {{.+}}, i32 1, i[[SZ]] {{4|8}}, i8* [[ARG_RL]], void (i8*, i16, i16, i16)* [[SHUFFLE_REDUCE_FN:@.+]], void (i8*, i32)* [[WARP_COPY_FN:@.+]], void (i8*, i8*, i32, i32)* [[SCRATCH_COPY_FN:@.+]], void (i8*, i8*, i32, i32, i32)* [[LOAD_REDUCE_FN:@.+]])
+ // CHECK: [[COND:%.+]] = icmp eq i32 [[RET]], 1
+ // CHECK: br i1 [[COND]], label {{%?}}[[IFLABEL:.+]], label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[IFLABEL]]
+ // CHECK: [[E_INV:%.+]] = load double, double* [[E_IN:%.+]], align
+ // CHECK: [[EV:%.+]] = load double, double* [[E]], align
+ // CHECK: [[ADD:%.+]] = fadd double [[E_INV]], [[EV]]
+ // CHECK: store double [[ADD]], double* [[E_IN]], align
+ // CHECK: call void @__kmpc_nvptx_end_reduce_nowait(
+ // CHECK: br label %[[EXIT]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: call void @__kmpc_kernel_deinit()
+
+ //
+ // Reduction function
+ // CHECK: define internal void [[REDUCTION_FUNC:@.+]](i8*, i8*)
+ // CHECK: [[VAR_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[VAR_RHS_VOID:%.+]] = load i8*, i8** [[VAR_RHS_REF]],
+ // CHECK: [[VAR_RHS:%.+]] = bitcast i8* [[VAR_RHS_VOID]] to double*
+ //
+ // CHECK: [[VAR_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[VAR_LHS_VOID:%.+]] = load i8*, i8** [[VAR_LHS_REF]],
+ // CHECK: [[VAR_LHS:%.+]] = bitcast i8* [[VAR_LHS_VOID]] to double*
+ //
+ // CHECK: [[VAR_LHS_VAL:%.+]] = load double, double* [[VAR_LHS]],
+ // CHECK: [[VAR_RHS_VAL:%.+]] = load double, double* [[VAR_RHS]],
+ // CHECK: [[RES:%.+]] = fadd double [[VAR_LHS_VAL]], [[VAR_RHS_VAL]]
+ // CHECK: store double [[RES]], double* [[VAR_LHS]],
+ // CHECK: ret void
+
+ //
+ // Shuffle and reduce function
+ // CHECK: define internal void [[SHUFFLE_REDUCE_FN]](i8*, i16 {{.*}}, i16 {{.*}}, i16 {{.*}})
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT:%.+]] = alloca double
+ //
+ // CHECK: [[LANEID:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[LANEOFFSET:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[ALGVER:%.+]] = load i16, i16* {{.+}}, align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: [[ELT_VAL:%.+]] = load double, double* [[ELT]], align
+ //
+ // CHECK: [[ELT_CAST:%.+]] = bitcast double [[ELT_VAL]] to i64
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT_VAL64:%.+]] = call i64 @__kmpc_shuffle_int64(i64 [[ELT_CAST]], i16 [[LANEOFFSET]], i16 [[WS]])
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = bitcast i64 [[REMOTE_ELT_VAL64]] to double
+ //
+ // CHECK: store double [[REMOTE_ELT_VAL]], double* [[REMOTE_ELT]], align
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = bitcast double* [[REMOTE_ELT]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT_VOID]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // Condition to reduce
+ // CHECK: [[CONDALG0:%.+]] = icmp eq i16 [[ALGVER]], 0
+ //
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp ult i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[CONDALG1:%.+]] = and i1 [[COND1]], [[COND2]]
+ //
+ // CHECK: [[COND3:%.+]] = icmp eq i16 [[ALGVER]], 2
+ // CHECK: [[COND4:%.+]] = and i16 [[LANEID]], 1
+ // CHECK: [[COND5:%.+]] = icmp eq i16 [[COND4]], 0
+ // CHECK: [[COND6:%.+]] = and i1 [[COND3]], [[COND5]]
+ // CHECK: [[COND7:%.+]] = icmp sgt i16 [[LANEOFFSET]], 0
+ // CHECK: [[CONDALG2:%.+]] = and i1 [[COND6]], [[COND7]]
+ //
+ // CHECK: [[COND8:%.+]] = or i1 [[CONDALG0]], [[CONDALG1]]
+ // CHECK: [[SHOULD_REDUCE:%.+]] = or i1 [[COND8]], [[CONDALG2]]
+ // CHECK: br i1 [[SHOULD_REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // Now check if we should just copy over the remote reduction list
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp uge i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[SHOULD_COPY:%.+]] = and i1 [[COND1]], [[COND2]]
+ // CHECK: br i1 [[SHOULD_COPY]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // CHECK: [[DO_COPY]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to double*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load double, double* [[REMOTE_ELT]], align
+ // CHECK: store double [[REMOTE_ELT_VAL]], double* [[ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // CHECK: [[COPY_CONT]]
+ // CHECK: void
+
+ //
+ // Inter warp copy function
+ // CHECK: define internal void [[WARP_COPY_FN]](i8*, i32)
+ // CHECK-DAG: [[LANEID:%.+]] = and i32 {{.+}}, 31
+ // CHECK-DAG: [[WARPID:%.+]] = ashr i32 {{.+}}, 5
+ // CHECK-DAG: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: [[ELT_VAL:%.+]] = load double, double* [[ELT]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to double addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store double [[ELT_VAL]], double addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to double addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load double, double addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: store double [[MEDIUM_ELT_VAL]], double* [[ELT]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: ret
+
+ //
+ // Copy to scratchpad function
+ // CHECK: define internal void [[SCRATCH_COPY_FN]](i8*, i8*, i32, i32)
+ // CHECK: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[SCRATCHPAD_PTR:%.+]] = load i8*, i8** {{.+}}, align
+ // CHECK-64: [[TEAM32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[TEAM:%.+]] = sext i32 [[TEAM32]] to i64
+ // CHECK-32: [[TEAM:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS:%.+]] = sext i32 [[NUM_TEAMS32]] to i64
+ // CHECK-32: [[NUM_TEAMS:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SCRATCHPAD:%.+]] = ptrtoint i8* [[SCRATCHPAD_PTR]] to i[[SZ]]
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 8, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = bitcast i8* [[SCRATCHPAD_ELT_PTR_VOID]] to double*
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: [[ELT_VAL:%.+]] = load double, double* [[ELT]], align
+ // CHECK: store double [[ELT_VAL]], double* [[SCRATCHPAD_ELT_PTR]], align
+ //
+ // CHECK: ret
+
+ //
+ // Load and reduce function
+ // CHECK: define internal void [[LOAD_REDUCE_FN]](i8*, i8*, i32, i32, i32)
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT:%.+]] = alloca double
+ // CHECK: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[SCRATCHPAD_PTR:%.+]] = load i8*, i8** {{.+}}, align
+ // CHECK-64: [[TEAM32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[TEAM:%.+]] = sext i32 [[TEAM32]] to i64
+ // CHECK-32: [[TEAM:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS:%.+]] = sext i32 [[NUM_TEAMS32]] to i64
+ // CHECK-32: [[NUM_TEAMS:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SHOULD_REDUCE:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SCRATCHPAD:%.+]] = ptrtoint i8* [[SCRATCHPAD_PTR]] to i[[SZ]]
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 8, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = bitcast i8* [[SCRATCHPAD_ELT_PTR_VOID]] to double*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load double, double* [[SCRATCHPAD_ELT_PTR]], align
+ // CHECK: store double [[REMOTE_ELT_VAL]], double* [[REMOTE_ELT]], align
+ // CHECK: [[REMOTE_ELT_PTR:%.+]] = bitcast double* [[REMOTE_ELT]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT_PTR]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[REDUCE:%.+]] = icmp eq i32 [[SHOULD_REDUCE]], 1
+ // CHECK: br i1 [[REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // Copy element from remote reduce list
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to double*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to double*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load double, double* [[REMOTE_ELT]], align
+ // CHECK: store double [[REMOTE_ELT_VAL]], double* [[ELT]], align
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // CHECK: ret
+
+
+
+
+
+
+
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l33}}_worker()
+
+ // CHECK: define {{.*}}void [[T2:@__omp_offloading_.+template.+l33]](
+ //
+ // CHECK: {{call|invoke}} void [[T2]]_worker()
+ //
+ // CHECK: call void @__kmpc_kernel_init(
+ //
+ // CHECK: store float {{1\.[0e\+]+}}, float* [[D:%.+]], align
+ // CHECK: [[C_VAL:%.+]] = load i8, i8* [[C:%.+]], align
+ // CHECK: [[CONV:%.+]] = sext i8 [[C_VAL]] to i32
+ // CHECK: [[XOR:%.+]] = xor i32 [[CONV]], 2
+ // CHECK: [[TRUNC:%.+]] = trunc i32 [[XOR]] to i8
+ // CHECK: store i8 [[TRUNC]], i8* [[C]], align
+ // CHECK: [[DV:%.+]] = load float, float* [[D]], align
+ // CHECK: [[MUL:%.+]] = fmul float [[DV]], {{[0-9e\.\+]+}}
+ // CHECK: store float [[MUL]], float* [[D]], align
+ // CHECK: [[PTR1:%.+]] = getelementptr inbounds [[RLT:.+]], [2 x i8*]* [[RL:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: store i8* [[C]], i8** [[PTR1]], align
+ // CHECK: [[PTR2:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RL]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[D_CAST:%.+]] = bitcast float* [[D]] to i8*
+ // CHECK: store i8* [[D_CAST]], i8** [[PTR2]], align
+ // CHECK: [[ARG_RL:%.+]] = bitcast [[RLT]]* [[RL]] to i8*
+ // CHECK: [[RET:%.+]] = call i32 @__kmpc_nvptx_teams_reduce_nowait(i32 {{.+}}, i32 2, i[[SZ]] {{8|16}}, i8* [[ARG_RL]], void (i8*, i16, i16, i16)* [[SHUFFLE_REDUCE_FN:@.+]], void (i8*, i32)* [[WARP_COPY_FN:@.+]], void (i8*, i8*, i32, i32)* [[SCRATCH_COPY_FN:@.+]], void (i8*, i8*, i32, i32, i32)* [[LOAD_REDUCE_FN:@.+]])
+ // CHECK: [[COND:%.+]] = icmp eq i32 [[RET]], 1
+ // CHECK: br i1 [[COND]], label {{%?}}[[IFLABEL:.+]], label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[IFLABEL]]
+ // CHECK: [[C_INV8:%.+]] = load i8, i8* [[C_IN:%.+]], align
+ // CHECK: [[C_INV:%.+]] = sext i8 [[C_INV8]] to i32
+ // CHECK: [[CV8:%.+]] = load i8, i8* [[C]], align
+ // CHECK: [[CV:%.+]] = sext i8 [[CV8]] to i32
+ // CHECK: [[XOR:%.+]] = xor i32 [[C_INV]], [[CV]]
+ // CHECK: [[TRUNC:%.+]] = trunc i32 [[XOR]] to i8
+ // CHECK: store i8 [[TRUNC]], i8* [[C_IN]], align
+ // CHECK: [[D_INV:%.+]] = load float, float* [[D_IN:%.+]], align
+ // CHECK: [[DV:%.+]] = load float, float* [[D]], align
+ // CHECK: [[MUL:%.+]] = fmul float [[D_INV]], [[DV]]
+ // CHECK: store float [[MUL]], float* [[D_IN]], align
+ // CHECK: call void @__kmpc_nvptx_end_reduce_nowait(
+ // CHECK: br label %[[EXIT]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: call void @__kmpc_kernel_deinit()
+
+ //
+ // Reduction function
+ // CHECK: define internal void [[REDUCTION_FUNC:@.+]](i8*, i8*)
+ // CHECK: [[VAR1_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[VAR1_RHS:%.+]] = load i8*, i8** [[VAR1_RHS_REF]],
+ //
+ // CHECK: [[VAR1_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[VAR1_LHS:%.+]] = load i8*, i8** [[VAR1_LHS_REF]],
+ //
+ // CHECK: [[VAR2_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[VAR2_RHS_VOID:%.+]] = load i8*, i8** [[VAR2_RHS_REF]],
+ // CHECK: [[VAR2_RHS:%.+]] = bitcast i8* [[VAR2_RHS_VOID]] to float*
+ //
+ // CHECK: [[VAR2_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[VAR2_LHS_VOID:%.+]] = load i8*, i8** [[VAR2_LHS_REF]],
+ // CHECK: [[VAR2_LHS:%.+]] = bitcast i8* [[VAR2_LHS_VOID]] to float*
+ //
+ // CHECK: [[VAR1_LHS_VAL8:%.+]] = load i8, i8* [[VAR1_LHS]],
+ // CHECK: [[VAR1_LHS_VAL:%.+]] = sext i8 [[VAR1_LHS_VAL8]] to i32
+ // CHECK: [[VAR1_RHS_VAL8:%.+]] = load i8, i8* [[VAR1_RHS]],
+ // CHECK: [[VAR1_RHS_VAL:%.+]] = sext i8 [[VAR1_RHS_VAL8]] to i32
+ // CHECK: [[XOR:%.+]] = xor i32 [[VAR1_LHS_VAL]], [[VAR1_RHS_VAL]]
+ // CHECK: [[RES:%.+]] = trunc i32 [[XOR]] to i8
+ // CHECK: store i8 [[RES]], i8* [[VAR1_LHS]],
+ //
+ // CHECK: [[VAR2_LHS_VAL:%.+]] = load float, float* [[VAR2_LHS]],
+ // CHECK: [[VAR2_RHS_VAL:%.+]] = load float, float* [[VAR2_RHS]],
+ // CHECK: [[RES:%.+]] = fmul float [[VAR2_LHS_VAL]], [[VAR2_RHS_VAL]]
+ // CHECK: store float [[RES]], float* [[VAR2_LHS]],
+ // CHECK: ret void
+
+ //
+ // Shuffle and reduce function
+ // CHECK: define internal void [[SHUFFLE_REDUCE_FN]](i8*, i16 {{.*}}, i16 {{.*}}, i16 {{.*}})
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT1:%.+]] = alloca i8
+ // CHECK: [[REMOTE_ELT2:%.+]] = alloca float
+ //
+ // CHECK: [[LANEID:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[LANEOFFSET:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[ALGVER:%.+]] = load i16, i16* {{.+}}, align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VAL:%.+]] = load i8, i8* [[ELT_VOID]], align
+ //
+ // CHECK: [[ELT_CAST:%.+]] = sext i8 [[ELT_VAL]] to i32
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT1_VAL32:%.+]] = call i32 @__kmpc_shuffle_int32(i32 [[ELT_CAST]], i16 [[LANEOFFSET]], i16 [[WS]])
+ // CHECK: [[REMOTE_ELT1_VAL:%.+]] = trunc i32 [[REMOTE_ELT1_VAL32]] to i8
+ //
+ // CHECK: store i8 [[REMOTE_ELT1_VAL]], i8* [[REMOTE_ELT1]], align
+ // CHECK: store i8* [[REMOTE_ELT1]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: [[ELT_VAL:%.+]] = load float, float* [[ELT]], align
+ //
+ // CHECK: [[ELT_CAST:%.+]] = bitcast float [[ELT_VAL]] to i32
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT2_VAL32:%.+]] = call i32 @__kmpc_shuffle_int32(i32 [[ELT_CAST]], i16 [[LANEOFFSET]], i16 [[WS]])
+ // CHECK: [[REMOTE_ELT2_VAL:%.+]] = bitcast i32 [[REMOTE_ELT2_VAL32]] to float
+ //
+ // CHECK: store float [[REMOTE_ELT2_VAL]], float* [[REMOTE_ELT2]], align
+ // CHECK: [[REMOTE_ELT2C:%.+]] = bitcast float* [[REMOTE_ELT2]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT2C]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // Condition to reduce
+ // CHECK: [[CONDALG0:%.+]] = icmp eq i16 [[ALGVER]], 0
+ //
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp ult i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[CONDALG1:%.+]] = and i1 [[COND1]], [[COND2]]
+ //
+ // CHECK: [[COND3:%.+]] = icmp eq i16 [[ALGVER]], 2
+ // CHECK: [[COND4:%.+]] = and i16 [[LANEID]], 1
+ // CHECK: [[COND5:%.+]] = icmp eq i16 [[COND4]], 0
+ // CHECK: [[COND6:%.+]] = and i1 [[COND3]], [[COND5]]
+ // CHECK: [[COND7:%.+]] = icmp sgt i16 [[LANEOFFSET]], 0
+ // CHECK: [[CONDALG2:%.+]] = and i1 [[COND6]], [[COND7]]
+ //
+ // CHECK: [[COND8:%.+]] = or i1 [[CONDALG0]], [[CONDALG1]]
+ // CHECK: [[SHOULD_REDUCE:%.+]] = or i1 [[COND8]], [[CONDALG2]]
+ // CHECK: br i1 [[SHOULD_REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // Now check if we should just copy over the remote reduction list
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp uge i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[SHOULD_COPY:%.+]] = and i1 [[COND1]], [[COND2]]
+ // CHECK: br i1 [[SHOULD_COPY]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // CHECK: [[DO_COPY]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i8, i8* [[REMOTE_ELT_VOID]], align
+ // CHECK: store i8 [[REMOTE_ELT_VAL]], i8* [[ELT_VOID]], align
+ //
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to float*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load float, float* [[REMOTE_ELT]], align
+ // CHECK: store float [[REMOTE_ELT_VAL]], float* [[ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // CHECK: [[COPY_CONT]]
+ // CHECK: void
+
+ //
+ // Inter warp copy function
+ // CHECK: define internal void [[WARP_COPY_FN]](i8*, i32)
+ // CHECK-DAG: [[LANEID:%.+]] = and i32 {{.+}}, 31
+ // CHECK-DAG: [[WARPID:%.+]] = ashr i32 {{.+}}, 5
+ // CHECK-DAG: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT_VAL:%.+]] = load i8, i8* [[ELT_VOID]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i8 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store i8 [[ELT_VAL]], i8 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i8 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load i8, i8 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: store i8 [[MEDIUM_ELT_VAL]], i8* [[ELT_VOID]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: [[ELT_VAL:%.+]] = load float, float* [[ELT]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to float addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store float [[ELT_VAL]], float addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to float addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load float, float addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: store float [[MEDIUM_ELT_VAL]], float* [[ELT]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: ret
+
+ //
+ // Copy to scratchpad function
+ // CHECK: define internal void [[SCRATCH_COPY_FN]](i8*, i8*, i32, i32)
+ // CHECK: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[SCRATCHPAD_PTR:%.+]] = load i8*, i8** {{.+}}, align
+ // CHECK-64: [[TEAM32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[TEAM:%.+]] = sext i32 [[TEAM32]] to i64
+ // CHECK-32: [[TEAM:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS:%.+]] = sext i32 [[NUM_TEAMS32]] to i64
+ // CHECK-32: [[NUM_TEAMS:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SCRATCHPAD:%.+]] = ptrtoint i8* [[SCRATCHPAD_PTR]] to i[[SZ]]
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 1, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+ // CHECK: [[ELT_VAL:%.+]] = load i8, i8* [[ELT_VOID]], align
+ // CHECK: store i8 [[ELT_VAL]], i8* [[SCRATCHPAD_ELT_PTR]], align
+ //
+ // CHECK: [[OF:%.+]] = mul i[[SZ]] [[NUM_TEAMS]], 1
+ // CHECK: [[POS1:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[OF]]
+ // CHECK: [[POS2:%.+]] = sub i[[SZ]] [[POS1]], 1
+ // CHECK: [[POS3:%.+]] = sdiv i[[SZ]] [[POS2]], 256
+ // CHECK: [[POS4:%.+]] = add i[[SZ]] [[POS3]], 1
+ // CHECK: [[SCRATCHPAD_NEXT:%.+]] = mul i[[SZ]] [[POS4]], 256
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 4, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD_NEXT]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = bitcast i8* [[SCRATCHPAD_ELT_PTR_VOID]] to float*
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: [[ELT_VAL:%.+]] = load float, float* [[ELT]], align
+ // CHECK: store float [[ELT_VAL]], float* [[SCRATCHPAD_ELT_PTR]], align
+ //
+ // CHECK: ret
+
+ //
+ // Load and reduce function
+ // CHECK: define internal void [[LOAD_REDUCE_FN]](i8*, i8*, i32, i32, i32)
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT1:%.+]] = alloca i8
+ // CHECK: [[REMOTE_ELT2:%.+]] = alloca float
+ // CHECK: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[SCRATCHPAD_PTR:%.+]] = load i8*, i8** {{.+}}, align
+ // CHECK-64: [[TEAM32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[TEAM:%.+]] = sext i32 [[TEAM32]] to i64
+ // CHECK-32: [[TEAM:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS:%.+]] = sext i32 [[NUM_TEAMS32]] to i64
+ // CHECK-32: [[NUM_TEAMS:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SHOULD_REDUCE:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SCRATCHPAD:%.+]] = ptrtoint i8* [[SCRATCHPAD_PTR]] to i[[SZ]]
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 1, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i8, i8* [[SCRATCHPAD_ELT_PTR_VOID]], align
+ // CHECK: store i8 [[REMOTE_ELT_VAL]], i8* [[REMOTE_ELT1]], align
+ // CHECK: store i8* [[REMOTE_ELT1]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[OF:%.+]] = mul i[[SZ]] [[NUM_TEAMS]], 1
+ // CHECK: [[POS1:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[OF]]
+ // CHECK: [[POS2:%.+]] = sub i[[SZ]] [[POS1]], 1
+ // CHECK: [[POS3:%.+]] = sdiv i[[SZ]] [[POS2]], 256
+ // CHECK: [[POS4:%.+]] = add i[[SZ]] [[POS3]], 1
+ // CHECK: [[SCRATCHPAD_NEXT:%.+]] = mul i[[SZ]] [[POS4]], 256
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 4, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD_NEXT]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = bitcast i8* [[SCRATCHPAD_ELT_PTR_VOID]] to float*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load float, float* [[SCRATCHPAD_ELT_PTR]], align
+ // CHECK: store float [[REMOTE_ELT_VAL]], float* [[REMOTE_ELT2]], align
+ // CHECK: [[REMOTE_ELT_PTR:%.+]] = bitcast float* [[REMOTE_ELT2]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT_PTR]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[REDUCE:%.+]] = icmp eq i32 [[SHOULD_REDUCE]], 1
+ // CHECK: br i1 [[REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // Copy element from remote reduce list
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i8, i8* [[REMOTE_ELT_VOID]], align
+ // CHECK: store i8 [[REMOTE_ELT_VAL]], i8* [[ELT_VOID]], align
+ //
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to float*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to float*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load float, float* [[REMOTE_ELT]], align
+ // CHECK: store float [[REMOTE_ELT_VAL]], float* [[ELT]], align
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // CHECK: ret
+
+
+
+
+
+
+
+
+
+
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l40}}_worker()
+
+ // CHECK: define {{.*}}void [[T3:@__omp_offloading_.+template.+l40]](
+ //
+ // CHECK: {{call|invoke}} void [[T3]]_worker()
+ //
+ // CHECK: call void @__kmpc_kernel_init(
+ //
+ // CHECK: store i32 0, i32* [[A:%.+]], align
+ // CHECK: store i16 -32768, i16* [[B:%.+]], align
+ // CHECK: [[A_VAL:%.+]] = load i32, i32* [[A:%.+]], align
+ // CHECK: [[OR:%.+]] = or i32 [[A_VAL]], 1
+ // CHECK: store i32 [[OR]], i32* [[A]], align
+ // CHECK: [[BV16:%.+]] = load i16, i16* [[B]], align
+ // CHECK: [[BV:%.+]] = sext i16 [[BV16]] to i32
+ // CHECK: [[CMP:%.+]] = icmp sgt i32 99, [[BV]]
+ // CHECK: br i1 [[CMP]], label {{%?}}[[DO_MAX:.+]], label {{%?}}[[MAX_ELSE:.+]]
+ //
+ // CHECK: [[DO_MAX]]
+ // CHECK: br label {{%?}}[[MAX_CONT:.+]]
+ //
+ // CHECK: [[MAX_ELSE]]
+ // CHECK: [[BV:%.+]] = load i16, i16* [[B]], align
+ // CHECK: [[MAX:%.+]] = sext i16 [[BV]] to i32
+ // CHECK: br label {{%?}}[[MAX_CONT]]
+ //
+ // CHECK: [[MAX_CONT]]
+ // CHECK: [[B_LVALUE:%.+]] = phi i32 [ 99, %[[DO_MAX]] ], [ [[MAX]], %[[MAX_ELSE]] ]
+ // CHECK: [[TRUNC:%.+]] = trunc i32 [[B_LVALUE]] to i16
+ // CHECK: store i16 [[TRUNC]], i16* [[B]], align
+ // CHECK: [[PTR1:%.+]] = getelementptr inbounds [[RLT:.+]], [2 x i8*]* [[RL:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[A_CAST:%.+]] = bitcast i32* [[A]] to i8*
+ // CHECK: store i8* [[A_CAST]], i8** [[PTR1]], align
+ // CHECK: [[PTR2:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RL]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[B_CAST:%.+]] = bitcast i16* [[B]] to i8*
+ // CHECK: store i8* [[B_CAST]], i8** [[PTR2]], align
+ // CHECK: [[ARG_RL:%.+]] = bitcast [[RLT]]* [[RL]] to i8*
+ // CHECK: [[RET:%.+]] = call i32 @__kmpc_nvptx_teams_reduce_nowait(i32 {{.+}}, i32 2, i[[SZ]] {{8|16}}, i8* [[ARG_RL]], void (i8*, i16, i16, i16)* [[SHUFFLE_REDUCE_FN:@.+]], void (i8*, i32)* [[WARP_COPY_FN:@.+]], void (i8*, i8*, i32, i32)* [[SCRATCH_COPY_FN:@.+]], void (i8*, i8*, i32, i32, i32)* [[LOAD_REDUCE_FN:@.+]])
+ // CHECK: [[COND:%.+]] = icmp eq i32 [[RET]], 1
+ // CHECK: br i1 [[COND]], label {{%?}}[[IFLABEL:.+]], label {{%?}}[[EXIT:.+]]
+ //
+ // CHECK: [[IFLABEL]]
+ // CHECK: [[A_INV:%.+]] = load i32, i32* [[A_IN:%.+]], align
+ // CHECK: [[AV:%.+]] = load i32, i32* [[A]], align
+ // CHECK: [[OR:%.+]] = or i32 [[A_INV]], [[AV]]
+ // CHECK: store i32 [[OR]], i32* [[A_IN]], align
+ // CHECK: [[B_INV16:%.+]] = load i16, i16* [[B_IN:%.+]], align
+ // CHECK: [[B_INV:%.+]] = sext i16 [[B_INV16]] to i32
+ // CHECK: [[BV16:%.+]] = load i16, i16* [[B]], align
+ // CHECK: [[BV:%.+]] = sext i16 [[BV16]] to i32
+ // CHECK: [[CMP:%.+]] = icmp sgt i32 [[B_INV]], [[BV]]
+ // CHECK: br i1 [[CMP]], label {{%?}}[[DO_MAX:.+]], label {{%?}}[[MAX_ELSE:.+]]
+ //
+ // CHECK: [[DO_MAX]]
+ // CHECK: [[MAX1:%.+]] = load i16, i16* [[B_IN]], align
+ // CHECK: br label {{%?}}[[MAX_CONT:.+]]
+ //
+ // CHECK: [[MAX_ELSE]]
+ // CHECK: [[MAX2:%.+]] = load i16, i16* [[B]], align
+ // CHECK: br label {{%?}}[[MAX_CONT]]
+ //
+ // CHECK: [[MAX_CONT]]
+ // CHECK: [[B_MAX:%.+]] = phi i16 [ [[MAX1]], %[[DO_MAX]] ], [ [[MAX2]], %[[MAX_ELSE]] ]
+ // CHECK: store i16 [[B_MAX]], i16* [[B_IN]], align
+ // CHECK: call void @__kmpc_nvptx_end_reduce_nowait(
+ // CHECK: br label %[[EXIT]]
+ //
+ // CHECK: [[EXIT]]
+ // CHECK: call void @__kmpc_kernel_deinit()
+
+ //
+ // Reduction function
+ // CHECK: define internal void [[REDUCTION_FUNC:@.+]](i8*, i8*)
+ // CHECK: [[VAR1_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[VAR1_RHS_VOID:%.+]] = load i8*, i8** [[VAR1_RHS_REF]],
+ // CHECK: [[VAR1_RHS:%.+]] = bitcast i8* [[VAR1_RHS_VOID]] to i32*
+ //
+ // CHECK: [[VAR1_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[VAR1_LHS_VOID:%.+]] = load i8*, i8** [[VAR1_LHS_REF]],
+ // CHECK: [[VAR1_LHS:%.+]] = bitcast i8* [[VAR1_LHS_VOID]] to i32*
+ //
+ // CHECK: [[VAR2_RHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_RHS]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[VAR2_RHS_VOID:%.+]] = load i8*, i8** [[VAR2_RHS_REF]],
+ // CHECK: [[VAR2_RHS:%.+]] = bitcast i8* [[VAR2_RHS_VOID]] to i16*
+ //
+ // CHECK: [[VAR2_LHS_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST_LHS]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[VAR2_LHS_VOID:%.+]] = load i8*, i8** [[VAR2_LHS_REF]],
+ // CHECK: [[VAR2_LHS:%.+]] = bitcast i8* [[VAR2_LHS_VOID]] to i16*
+ //
+ // CHECK: [[VAR1_LHS_VAL:%.+]] = load i32, i32* [[VAR1_LHS]],
+ // CHECK: [[VAR1_RHS_VAL:%.+]] = load i32, i32* [[VAR1_RHS]],
+ // CHECK: [[OR:%.+]] = or i32 [[VAR1_LHS_VAL]], [[VAR1_RHS_VAL]]
+ // CHECK: store i32 [[OR]], i32* [[VAR1_LHS]],
+ //
+ // CHECK: [[VAR2_LHS_VAL16:%.+]] = load i16, i16* [[VAR2_LHS]],
+ // CHECK: [[VAR2_LHS_VAL:%.+]] = sext i16 [[VAR2_LHS_VAL16]] to i32
+ // CHECK: [[VAR2_RHS_VAL16:%.+]] = load i16, i16* [[VAR2_RHS]],
+ // CHECK: [[VAR2_RHS_VAL:%.+]] = sext i16 [[VAR2_RHS_VAL16]] to i32
+ //
+ // CHECK: [[CMP:%.+]] = icmp sgt i32 [[VAR2_LHS_VAL]], [[VAR2_RHS_VAL]]
+ // CHECK: br i1 [[CMP]], label {{%?}}[[DO_MAX:.+]], label {{%?}}[[MAX_ELSE:.+]]
+ //
+ // CHECK: [[DO_MAX]]
+ // CHECK: [[MAX1:%.+]] = load i16, i16* [[VAR2_LHS]], align
+ // CHECK: br label {{%?}}[[MAX_CONT:.+]]
+ //
+ // CHECK: [[MAX_ELSE]]
+ // CHECK: [[MAX2:%.+]] = load i16, i16* [[VAR2_RHS]], align
+ // CHECK: br label {{%?}}[[MAX_CONT]]
+ //
+ // CHECK: [[MAX_CONT]]
+ // CHECK: [[MAXV:%.+]] = phi i16 [ [[MAX1]], %[[DO_MAX]] ], [ [[MAX2]], %[[MAX_ELSE]] ]
+ // CHECK: store i16 [[MAXV]], i16* [[VAR2_LHS]],
+ // CHECK: ret void
+
+ //
+ // Shuffle and reduce function
+ // CHECK: define internal void [[SHUFFLE_REDUCE_FN]](i8*, i16 {{.*}}, i16 {{.*}}, i16 {{.*}})
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT1:%.+]] = alloca i32
+ // CHECK: [[REMOTE_ELT2:%.+]] = alloca i16
+ //
+ // CHECK: [[LANEID:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[LANEOFFSET:%.+]] = load i16, i16* {{.+}}, align
+ // CHECK: [[ALGVER:%.+]] = load i16, i16* {{.+}}, align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: [[ELT_VAL:%.+]] = load i32, i32* [[ELT]], align
+ //
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT1_VAL:%.+]] = call i32 @__kmpc_shuffle_int32(i32 [[ELT_VAL]], i16 [[LANEOFFSET]], i16 [[WS]])
+ //
+ // CHECK: store i32 [[REMOTE_ELT1_VAL]], i32* [[REMOTE_ELT1]], align
+ // CHECK: [[REMOTE_ELT1C:%.+]] = bitcast i32* [[REMOTE_ELT1]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT1C]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: [[ELT_VAL:%.+]] = load i16, i16* [[ELT]], align
+ //
+ // CHECK: [[ELT_CAST:%.+]] = sext i16 [[ELT_VAL]] to i32
+ // CHECK: [[WS32:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[WS:%.+]] = trunc i32 [[WS32]] to i16
+ // CHECK: [[REMOTE_ELT2_VAL32:%.+]] = call i32 @__kmpc_shuffle_int32(i32 [[ELT_CAST]], i16 [[LANEOFFSET]], i16 [[WS]])
+ // CHECK: [[REMOTE_ELT2_VAL:%.+]] = trunc i32 [[REMOTE_ELT2_VAL32]] to i16
+ //
+ // CHECK: store i16 [[REMOTE_ELT2_VAL]], i16* [[REMOTE_ELT2]], align
+ // CHECK: [[REMOTE_ELT2C:%.+]] = bitcast i16* [[REMOTE_ELT2]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT2C]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // Condition to reduce
+ // CHECK: [[CONDALG0:%.+]] = icmp eq i16 [[ALGVER]], 0
+ //
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp ult i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[CONDALG1:%.+]] = and i1 [[COND1]], [[COND2]]
+ //
+ // CHECK: [[COND3:%.+]] = icmp eq i16 [[ALGVER]], 2
+ // CHECK: [[COND4:%.+]] = and i16 [[LANEID]], 1
+ // CHECK: [[COND5:%.+]] = icmp eq i16 [[COND4]], 0
+ // CHECK: [[COND6:%.+]] = and i1 [[COND3]], [[COND5]]
+ // CHECK: [[COND7:%.+]] = icmp sgt i16 [[LANEOFFSET]], 0
+ // CHECK: [[CONDALG2:%.+]] = and i1 [[COND6]], [[COND7]]
+ //
+ // CHECK: [[COND8:%.+]] = or i1 [[CONDALG0]], [[CONDALG1]]
+ // CHECK: [[SHOULD_REDUCE:%.+]] = or i1 [[COND8]], [[CONDALG2]]
+ // CHECK: br i1 [[SHOULD_REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // Now check if we should just copy over the remote reduction list
+ // CHECK: [[COND1:%.+]] = icmp eq i16 [[ALGVER]], 1
+ // CHECK: [[COND2:%.+]] = icmp uge i16 [[LANEID]], [[LANEOFFSET]]
+ // CHECK: [[SHOULD_COPY:%.+]] = and i1 [[COND1]], [[COND2]]
+ // CHECK: br i1 [[SHOULD_COPY]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // CHECK: [[DO_COPY]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to i32*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i32, i32* [[REMOTE_ELT]], align
+ // CHECK: store i32 [[REMOTE_ELT_VAL]], i32* [[ELT]], align
+ //
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to i16*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i16, i16* [[REMOTE_ELT]], align
+ // CHECK: store i16 [[REMOTE_ELT_VAL]], i16* [[ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // CHECK: [[COPY_CONT]]
+ // CHECK: void
+
+ //
+ // Inter warp copy function
+ // CHECK: define internal void [[WARP_COPY_FN]](i8*, i32)
+ // CHECK-DAG: [[LANEID:%.+]] = and i32 {{.+}}, 31
+ // CHECK-DAG: [[WARPID:%.+]] = ashr i32 {{.+}}, 5
+ // CHECK-DAG: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: [[ELT_VAL:%.+]] = load i32, i32* [[ELT]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i32 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store i32 [[ELT_VAL]], i32 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i32 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load i32, i32 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: store i32 [[MEDIUM_ELT_VAL]], i32* [[ELT]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: [[IS_WARP_MASTER:%.+]] = icmp eq i32 [[LANEID]], 0
+ // CHECK: br i1 [[IS_WARP_MASTER]], label {{%?}}[[DO_COPY:.+]], label {{%?}}[[COPY_ELSE:.+]]
+ //
+ // [[DO_COPY]]
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: [[ELT_VAL:%.+]] = load i16, i16* [[ELT]], align
+ //
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[WARPID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i16 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: store i16 [[ELT_VAL]], i16 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: br label {{%?}}[[COPY_CONT:.+]]
+ //
+ // CHECK: [[COPY_ELSE]]
+ // CHECK: br label {{%?}}[[COPY_CONT]]
+ //
+ // Barrier after copy to shared memory storage medium.
+ // CHECK: [[COPY_CONT]]
+ // CHECK: [[WS:%.+]] = call i32 @llvm.nvvm.read.ptx.sreg.warpsize()
+ // CHECK: [[ACTIVE_THREADS:%.+]] = mul nsw i32 [[ACTIVE_WARPS:%.+]], [[WS]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ //
+ // Read into warp 0.
+ // CHECK: [[IS_W0_ACTIVE_THREAD:%.+]] = icmp ult i32 [[TID:%.+]], [[ACTIVE_WARPS]]
+ // CHECK: br i1 [[IS_W0_ACTIVE_THREAD]], label {{%?}}[[DO_READ:.+]], label {{%?}}[[READ_ELSE:.+]]
+ //
+ // CHECK: [[DO_READ]]
+ // CHECK: [[MEDIUM_ELT64:%.+]] = getelementptr inbounds [32 x i64], [32 x i64] addrspace([[SHARED_ADDRSPACE]])* [[TRANSFER_STORAGE]], i64 0, i32 [[TID]]
+ // CHECK: [[MEDIUM_ELT:%.+]] = bitcast i64 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT64]] to i16 addrspace([[SHARED_ADDRSPACE]])*
+ // CHECK: [[MEDIUM_ELT_VAL:%.+]] = load i16, i16 addrspace([[SHARED_ADDRSPACE]])* [[MEDIUM_ELT]], align
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: store i16 [[MEDIUM_ELT_VAL]], i16* [[ELT]], align
+ // CHECK: br label {{%?}}[[READ_CONT:.+]]
+ //
+ // CHECK: [[READ_ELSE]]
+ // CHECK: br label {{%?}}[[READ_CONT]]
+ //
+ // CHECK: [[READ_CONT]]
+ // CHECK: call void @llvm.nvvm.barrier(i32 1, i32 [[ACTIVE_THREADS]])
+ // CHECK: ret
+
+ //
+ // Copy to scratchpad function
+ // CHECK: define internal void [[SCRATCH_COPY_FN]](i8*, i8*, i32, i32)
+ // CHECK: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[SCRATCHPAD_PTR:%.+]] = load i8*, i8** {{.+}}, align
+ // CHECK-64: [[TEAM32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[TEAM:%.+]] = sext i32 [[TEAM32]] to i64
+ // CHECK-32: [[TEAM:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS:%.+]] = sext i32 [[NUM_TEAMS32]] to i64
+ // CHECK-32: [[NUM_TEAMS:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SCRATCHPAD:%.+]] = ptrtoint i8* [[SCRATCHPAD_PTR]] to i[[SZ]]
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 4, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = bitcast i8* [[SCRATCHPAD_ELT_PTR_VOID]] to i32*
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: [[ELT_VAL:%.+]] = load i32, i32* [[ELT]], align
+ // CHECK: store i32 [[ELT_VAL]], i32* [[SCRATCHPAD_ELT_PTR]], align
+ //
+ // CHECK: [[OF:%.+]] = mul i[[SZ]] [[NUM_TEAMS]], 4
+ // CHECK: [[POS1:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[OF]]
+ // CHECK: [[POS2:%.+]] = sub i[[SZ]] [[POS1]], 1
+ // CHECK: [[POS3:%.+]] = sdiv i[[SZ]] [[POS2]], 256
+ // CHECK: [[POS4:%.+]] = add i[[SZ]] [[POS3]], 1
+ // CHECK: [[SCRATCHPAD_NEXT:%.+]] = mul i[[SZ]] [[POS4]], 256
+ //
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 2, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD_NEXT]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = bitcast i8* [[SCRATCHPAD_ELT_PTR_VOID]] to i16*
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: [[ELT_VAL:%.+]] = load i16, i16* [[ELT]], align
+ // CHECK: store i16 [[ELT_VAL]], i16* [[SCRATCHPAD_ELT_PTR]], align
+ //
+ // CHECK: ret
+
+ //
+ // Load and reduce function
+ // CHECK: define internal void [[LOAD_REDUCE_FN]](i8*, i8*, i32, i32, i32)
+ // CHECK: [[REMOTE_RED_LIST:%.+]] = alloca [[RLT]], align
+ // CHECK: [[REMOTE_ELT1:%.+]] = alloca i32
+ // CHECK: [[REMOTE_ELT2:%.+]] = alloca i16
+ // CHECK: [[RED_LIST:%.+]] = bitcast i8* {{.+}} to [[RLT]]*
+ // CHECK: [[SCRATCHPAD_PTR:%.+]] = load i8*, i8** {{.+}}, align
+ // CHECK-64: [[TEAM32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[TEAM:%.+]] = sext i32 [[TEAM32]] to i64
+ // CHECK-32: [[TEAM:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS32:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK-64: [[NUM_TEAMS:%.+]] = sext i32 [[NUM_TEAMS32]] to i64
+ // CHECK-32: [[NUM_TEAMS:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SHOULD_REDUCE:%.+]] = load i32, i32* {{.+}}, align
+ // CHECK: [[SCRATCHPAD:%.+]] = ptrtoint i8* [[SCRATCHPAD_PTR]] to i[[SZ]]
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 4, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = bitcast i8* [[SCRATCHPAD_ELT_PTR_VOID]] to i32*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i32, i32* [[SCRATCHPAD_ELT_PTR]], align
+ // CHECK: store i32 [[REMOTE_ELT_VAL]], i32* [[REMOTE_ELT1]], align
+ // CHECK: [[REMOTE_ELT1_PTR:%.+]] = bitcast i32* [[REMOTE_ELT1]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT1_PTR]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[OF:%.+]] = mul i[[SZ]] [[NUM_TEAMS]], 4
+ // CHECK: [[POS1:%.+]] = add i[[SZ]] [[SCRATCHPAD]], [[OF]]
+ // CHECK: [[POS2:%.+]] = sub i[[SZ]] [[POS1]], 1
+ // CHECK: [[POS3:%.+]] = sdiv i[[SZ]] [[POS2]], 256
+ // CHECK: [[POS4:%.+]] = add i[[SZ]] [[POS3]], 1
+ // CHECK: [[SCRATCHPAD_NEXT:%.+]] = mul i[[SZ]] [[POS4]], 256
+ //
+ // CHECK: [[P:%.+]] = mul i[[SZ]] 2, [[TEAM]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR64:%.+]] = add i[[SZ]] [[SCRATCHPAD_NEXT]], [[P]]
+ // CHECK: [[SCRATCHPAD_ELT_PTR_VOID:%.+]] = inttoptr i[[SZ]] [[SCRATCHPAD_ELT_PTR64]] to i8*
+
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[SCRATCHPAD_ELT_PTR:%.+]] = bitcast i8* [[SCRATCHPAD_ELT_PTR_VOID]] to i16*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i16, i16* [[SCRATCHPAD_ELT_PTR]], align
+ // CHECK: store i16 [[REMOTE_ELT_VAL]], i16* [[REMOTE_ELT2]], align
+ // CHECK: [[REMOTE_ELT_PTR:%.+]] = bitcast i16* [[REMOTE_ELT2]] to i8*
+ // CHECK: store i8* [[REMOTE_ELT_PTR]], i8** [[REMOTE_ELT_REF]], align
+ //
+ // CHECK: [[REDUCE:%.+]] = icmp eq i32 [[SHOULD_REDUCE]], 1
+ // CHECK: br i1 [[REDUCE]], label {{%?}}[[DO_REDUCE:.+]], label {{%?}}[[REDUCE_ELSE:.+]]
+ //
+ // CHECK: [[DO_REDUCE]]
+ // CHECK: [[RED_LIST1_VOID:%.+]] = bitcast [[RLT]]* [[RED_LIST]] to i8*
+ // CHECK: [[RED_LIST2_VOID:%.+]] = bitcast [[RLT]]* [[REMOTE_RED_LIST]] to i8*
+ // CHECK: call void [[REDUCTION_FUNC]](i8* [[RED_LIST1_VOID]], i8* [[RED_LIST2_VOID]])
+ // CHECK: br label {{%?}}[[REDUCE_CONT:.+]]
+ //
+ // Copy element from remote reduce list
+ // CHECK: [[REDUCE_ELSE]]
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 0
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i32*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to i32*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i32, i32* [[REMOTE_ELT]], align
+ // CHECK: store i32 [[REMOTE_ELT_VAL]], i32* [[ELT]], align
+ //
+ // CHECK: [[REMOTE_ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[REMOTE_RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[REMOTE_ELT_VOID:%.+]] = load i8*, i8** [[REMOTE_ELT_REF]],
+ // CHECK: [[ELT_REF:%.+]] = getelementptr inbounds [[RLT]], [[RLT]]* [[RED_LIST:%.+]], i[[SZ]] 0, i[[SZ]] 1
+ // CHECK: [[ELT_VOID:%.+]] = load i8*, i8** [[ELT_REF]],
+ // CHECK: [[ELT:%.+]] = bitcast i8* [[ELT_VOID]] to i16*
+ // CHECK: [[REMOTE_ELT:%.+]] = bitcast i8* [[REMOTE_ELT_VOID]] to i16*
+ // CHECK: [[REMOTE_ELT_VAL:%.+]] = load i16, i16* [[REMOTE_ELT]], align
+ // CHECK: store i16 [[REMOTE_ELT_VAL]], i16* [[ELT]], align
+ // CHECK: br label {{%?}}[[REDUCE_CONT]]
+ //
+ // CHECK: [[REDUCE_CONT]]
+ // CHECK: ret
+
+
+#endif
diff --git a/test/OpenMP/openmp_check.cpp b/test/OpenMP/openmp_check.cpp
index c9b5eb0b9cba..d46213a90e9f 100644
--- a/test/OpenMP/openmp_check.cpp
+++ b/test/OpenMP/openmp_check.cpp
@@ -1,15 +1,35 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 %s
+
int nested(int a) {
#pragma omp parallel
++a;
- auto F = [&]() { // expected-error {{expected expression}} expected-error {{expected ';' at end of declaration}} expected-warning {{'auto' type specifier is a C++11 extension}}
+ auto F = [&]() {
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{'auto' type specifier is a C++11 extension}}
+ // expected-error@-3 {{expected expression}}
+ // expected-error@-4 {{expected ';' at end of declaration}}
+#else
+ // expected-no-diagnostics
+#endif
+
#pragma omp parallel
{
#pragma omp target
++a;
}
};
- F(); // expected-error {{C++ requires a type specifier for all declarations}}
- return a; // expected-error {{expected unqualified-id}}
-}// expected-error {{extraneous closing brace ('}')}}
+ F();
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{C++ requires a type specifier for all declarations}}
+#endif
+ return a;
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{expected unqualified-id}}
+#endif
+}
+#if __cplusplus <= 199711L
+// expected-error@-2 {{extraneous closing brace ('}')}}
+#endif
diff --git a/test/OpenMP/ordered_messages.cpp b/test/OpenMP/ordered_messages.cpp
index 36f9bb2c7777..eb2c18e4690c 100644
--- a/test/OpenMP/ordered_messages.cpp
+++ b/test/OpenMP/ordered_messages.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++98 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s
int foo();
@@ -123,6 +125,9 @@ T foo() {
#pragma omp ordered depend(sink : j, i) // expected-error {{expected 'i' loop iteration variable}} expected-error {{expected 'j' loop iteration variable}}
#pragma omp ordered depend(sink : i, j, k) // expected-error {{unexpected expression: number of expressions is larger than the number of associated loops}}
#pragma omp ordered depend(sink : i+foo(), j/4) // expected-error {{expression is not an integral constant expression}} expected-error {{expected '+' or '-' operation}}
+#if __cplusplus >= 201103L
+// expected-note@-2 {{non-constexpr function 'foo' cannot be used in a constant expression}}
+#endif
#pragma omp ordered depend(sink : i*0, j-4)// expected-error {{expected '+' or '-' operation}}
#pragma omp ordered depend(sink : i-0, j+sizeof(T)) depend(sink : i-0, j+sizeof(T))
#pragma omp ordered depend(sink : i-0, j+sizeof(T)) depend(source) // expected-error {{'depend(source)' clause cannot be mixed with 'depend(sink:vec)' clauses}}
@@ -133,6 +138,9 @@ T foo() {
}
int foo() {
+#if __cplusplus >= 201103L
+// expected-note@-2 2 {{declared here}}
+#endif
int k;
#pragma omp for ordered
for (int i = 0; i < 10; ++i) {
@@ -252,6 +260,9 @@ int k;
#pragma omp ordered depend(sink : j, i) // expected-error {{expected 'i' loop iteration variable}} expected-error {{expected 'j' loop iteration variable}}
#pragma omp ordered depend(sink : i, j, k) // expected-error {{unexpected expression: number of expressions is larger than the number of associated loops}}
#pragma omp ordered depend(sink : i+foo(), j/4) // expected-error {{expression is not an integral constant expression}} expected-error {{expected '+' or '-' operation}}
+#if __cplusplus >= 201103L
+// expected-note@-2 {{non-constexpr function 'foo' cannot be used in a constant expression}}
+#endif
#pragma omp ordered depend(sink : i*0, j-4)// expected-error {{expected '+' or '-' operation}}
#pragma omp ordered depend(sink : i-0, j+sizeof(int)) depend(sink : i-0, j+sizeof(int))
#pragma omp ordered depend(sink : i-0, j+sizeof(int)) depend(source) // expected-error {{'depend(source)' clause cannot be mixed with 'depend(sink:vec)' clauses}}
diff --git a/test/OpenMP/target_parallel_codegen.cpp b/test/OpenMP/target_parallel_codegen.cpp
new file mode 100644
index 000000000000..c7acb27cab74
--- /dev/null
+++ b/test/OpenMP/target_parallel_codegen.cpp
@@ -0,0 +1,802 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: %ident_t = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[STR:@.+]] = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00"
+// CHECK-DAG: [[DEF_LOC:@.+]] = private unnamed_addr constant %ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
+
+// CHECK-DAG: [[TT:%.+]] = type { i64, i8 }
+// CHECK-DAG: [[S1:%.+]] = type { double }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+
+// We have 8 target regions, but only 7 that actually will generate offloading
+// code, only 6 will have mapped arguments, and only 4 have all-constant map
+// sizes.
+
+// CHECK-DAG: [[SIZET2:@.+]] = private unnamed_addr constant [1 x i{{32|64}}] [i[[SZ:32|64]] 2]
+// CHECK-DAG: [[MAPT2:@.+]] = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: [[SIZET3:@.+]] = private unnamed_addr constant [2 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2]
+// CHECK-DAG: [[MAPT3:@.+]] = private unnamed_addr constant [2 x i32] [i32 288, i32 288]
+// CHECK-DAG: [[MAPT4:@.+]] = private unnamed_addr constant [9 x i32] [i32 288, i32 35, i32 288, i32 35, i32 35, i32 288, i32 288, i32 35, i32 35]
+// CHECK-DAG: [[SIZET5:@.+]] = private unnamed_addr constant [3 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2, i[[SZ]] 40]
+// CHECK-DAG: [[MAPT5:@.+]] = private unnamed_addr constant [3 x i32] [i32 288, i32 288, i32 35]
+// CHECK-DAG: [[SIZET6:@.+]] = private unnamed_addr constant [4 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2, i[[SZ]] 1, i[[SZ]] 40]
+// CHECK-DAG: [[MAPT6:@.+]] = private unnamed_addr constant [4 x i32] [i32 288, i32 288, i32 288, i32 35]
+// CHECK-DAG: [[MAPT7:@.+]] = private unnamed_addr constant [5 x i32] [i32 35, i32 288, i32 288, i32 288, i32 35]
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK-NOT: @{{.+}} = constant [[ENTTY]]
+
+// Check if offloading descriptor is created.
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// Check target registration is registered as a Ctor.
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+
+template<typename tx, typename ty>
+struct TT{
+ tx X;
+ ty Y;
+};
+
+// CHECK: define {{.*}}[[FOO:@.+]](
+int foo(int n) {
+ int a = 0;
+ short aa = 0;
+ float b[10];
+ float bn[n];
+ double c[5][10];
+ double cn[5][n];
+ TT<long long, char> d;
+
+ // CHECK: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 0, i8** null, i8** null, i[[SZ]]* null, i32* null, i32 1, i32 0)
+ // CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT0:@.+]]()
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target parallel
+ {
+ }
+
+ // CHECK: store i32 0, i32* [[RHV:%.+]], align 4
+ // CHECK: store i32 -1, i32* [[RHV]], align 4
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK: call void [[HVT1:@.+]](i[[SZ]] {{[^,]+}})
+ #pragma omp target parallel if(target: 0)
+ {
+ a += 1;
+ }
+
+ // CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, i8** [[BP:%[^,]+]], i8** [[P:%[^,]+]], i[[SZ]]* getelementptr inbounds ([1 x i[[SZ]]], [1 x i[[SZ]]]* [[SIZET2]], i32 0, i32 0), i32* getelementptr inbounds ([1 x i32], [1 x i32]* [[MAPT2]], i32 0, i32 0), i32 1, i32 0)
+ // CHECK-DAG: [[BP]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[BPR:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[P]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PR:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[BPR]], i32 0, i32 [[IDX0:[0-9]+]]
+ // CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PR]], i32 0, i32 [[IDX0]]
+ // CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
+ // CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
+ // CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+
+ // CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT2:@.+]](i[[SZ]] {{[^,]+}})
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target parallel if(target: 1)
+ {
+ aa += 1;
+ }
+
+ // CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 10
+ // CHECK: br i1 [[IF]], label %[[IFTHEN:[^,]+]], label %[[IFELSE:[^,]+]]
+ // CHECK: [[IFTHEN]]
+ // CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 2, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* getelementptr inbounds ([2 x i[[SZ]]], [2 x i[[SZ]]]* [[SIZET3]], i32 0, i32 0), i32* getelementptr inbounds ([2 x i32], [2 x i32]* [[MAPT3]], i32 0, i32 0), i32 1, i32 0)
+ // CHECK-DAG: [[BPR]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BP:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[PR]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[P:%[^,]+]], i32 0, i32 0
+
+ // CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BP]], i32 0, i32 0
+ // CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[P]], i32 0, i32 0
+ // CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
+ // CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
+ // CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+
+ // CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BP]], i32 0, i32 1
+ // CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[P]], i32 0, i32 1
+ // CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
+ // CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
+ // CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P1]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+ // CHECK-NEXT: br label %[[IFEND:.+]]
+
+ // CHECK: [[IFELSE]]
+ // CHECK: store i32 -1, i32* [[RHV]], align 4
+ // CHECK-NEXT: br label %[[IFEND:.+]]
+
+ // CHECK: [[IFEND]]
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT3:@.+]]({{[^,]+}}, {{[^,]+}})
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target parallel if(target: n>10)
+ {
+ a += 1;
+ aa += 1;
+ }
+
+ // We capture 3 VLA sizes in this target region
+ // CHECK-64: [[A_VAL:%.+]] = load i32, i32* %{{.+}},
+ // CHECK-64: [[A_ADDR:%.+]] = bitcast i[[SZ]]* [[A_CADDR:%.+]] to i32*
+ // CHECK-64: store i32 [[A_VAL]], i32* [[A_ADDR]],
+ // CHECK-64: [[A_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[A_CADDR]],
+
+ // CHECK-32: [[A_VAL:%.+]] = load i32, i32* %{{.+}},
+ // CHECK-32: store i32 [[A_VAL]], i32* [[A_CADDR:%.+]],
+ // CHECK-32: [[A_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[A_CADDR]],
+
+ // CHECK: [[BNSIZE:%.+]] = mul nuw i[[SZ]] [[VLA0:%.+]], 4
+ // CHECK: [[CNELEMSIZE2:%.+]] = mul nuw i[[SZ]] 5, [[VLA1:%.+]]
+ // CHECK: [[CNSIZE:%.+]] = mul nuw i[[SZ]] [[CNELEMSIZE2]], 8
+
+ // CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 20
+ // CHECK: br i1 [[IF]], label %[[TRY:[^,]+]], label %[[FAIL:[^,]+]]
+ // CHECK: [[TRY]]
+ // CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 9, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* [[SR:%[^,]+]], i32* getelementptr inbounds ([9 x i32], [9 x i32]* [[MAPT4]], i32 0, i32 0), i32 1, i32 0)
+ // CHECK-DAG: [[BPR]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[PR]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[SR]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S:%[^,]+]], i32 0, i32 0
+
+ // CHECK-DAG: [[SADDR0:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX0:[0-9]+]]
+ // CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX0]]
+ // CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX0]]
+ // CHECK-DAG: [[SADDR1:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX1:[0-9]+]]
+ // CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX1]]
+ // CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX1]]
+ // CHECK-DAG: [[SADDR2:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX2:[0-9]+]]
+ // CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX2]]
+ // CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX2]]
+ // CHECK-DAG: [[SADDR3:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX3:[0-9]+]]
+ // CHECK-DAG: [[BPADDR3:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX3]]
+ // CHECK-DAG: [[PADDR3:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX3]]
+ // CHECK-DAG: [[SADDR4:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX4:[0-9]+]]
+ // CHECK-DAG: [[BPADDR4:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX4]]
+ // CHECK-DAG: [[PADDR4:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX4]]
+ // CHECK-DAG: [[SADDR5:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX5:[0-9]+]]
+ // CHECK-DAG: [[BPADDR5:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX5]]
+ // CHECK-DAG: [[PADDR5:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX5]]
+ // CHECK-DAG: [[SADDR6:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX6:[0-9]+]]
+ // CHECK-DAG: [[BPADDR6:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX6]]
+ // CHECK-DAG: [[PADDR6:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX6]]
+ // CHECK-DAG: [[SADDR7:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX7:[0-9]+]]
+ // CHECK-DAG: [[BPADDR7:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX7]]
+ // CHECK-DAG: [[PADDR7:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX7]]
+ // CHECK-DAG: [[SADDR8:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX8:[0-9]+]]
+ // CHECK-DAG: [[BPADDR8:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX8]]
+ // CHECK-DAG: [[PADDR8:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX8]]
+
+ // The names below are not necessarily consistent with the names used for the
+ // addresses above as some are repeated.
+ // CHECK-DAG: [[BP0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+ // CHECK-DAG: [[P0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+ // CHECK-DAG: store i8* [[BP0]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P0]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP1:%[^,]+]] = inttoptr i[[SZ]] [[VLA1]] to i8*
+ // CHECK-DAG: [[P1:%[^,]+]] = inttoptr i[[SZ]] [[VLA1]] to i8*
+ // CHECK-DAG: store i8* [[BP1]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P1]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: store i8* inttoptr (i[[SZ]] 5 to i8*), i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* inttoptr (i[[SZ]] 5 to i8*), i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP3:%[^,]+]] = inttoptr i[[SZ]] [[A_CVAL]] to i8*
+ // CHECK-DAG: [[P3:%[^,]+]] = inttoptr i[[SZ]] [[A_CVAL]] to i8*
+ // CHECK-DAG: store i8* [[BP3]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P3]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] 4, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP4:%[^,]+]] = bitcast [10 x float]* %{{.+}} to i8*
+ // CHECK-DAG: [[P4:%[^,]+]] = bitcast [10 x float]* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP4]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P4]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] 40, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP5:%[^,]+]] = bitcast float* %{{.+}} to i8*
+ // CHECK-DAG: [[P5:%[^,]+]] = bitcast float* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP5]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P5]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] [[BNSIZE]], i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP6:%[^,]+]] = bitcast [5 x [10 x double]]* %{{.+}} to i8*
+ // CHECK-DAG: [[P6:%[^,]+]] = bitcast [5 x [10 x double]]* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP6]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P6]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] 400, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP7:%[^,]+]] = bitcast double* %{{.+}} to i8*
+ // CHECK-DAG: [[P7:%[^,]+]] = bitcast double* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP7]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P7]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] [[CNSIZE]], i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP8:%[^,]+]] = bitcast [[TT]]* %{{.+}} to i8*
+ // CHECK-DAG: [[P8:%[^,]+]] = bitcast [[TT]]* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP8]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P8]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] {{12|16}}, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT4:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target parallel if(target: n>20)
+ {
+ a += 1;
+ b[2] += 1.0;
+ bn[3] += 1.0;
+ c[1][2] += 1.0;
+ cn[1][3] += 1.0;
+ d.X += 1;
+ d.Y += 1;
+ }
+
+ return a;
+}
+
+// Check that the offloading functions are emitted and that the arguments are
+// correct and loaded correctly for the target regions in foo().
+
+// CHECK: define internal void [[HVT0]]()
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*))
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid.)
+// CHECK: ret void
+// CHECK-NEXT: }
+
+
+// CHECK: define internal void [[HVT1]](i[[SZ]] %{{.+}})
+// Create stack storage and store argument in there.
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i32*
+// CHECK-64: [[AA:%.+]] = load i32, i32* [[AA_CADDR]], align
+// CHECK-32: [[AA:%.+]] = load i32, i32* [[AA_ADDR]], align
+// CHECK-64: [[AA_C:%.+]] = bitcast i[[SZ]]* [[AA_CASTED]] to i32*
+// CHECK-64: store i32 [[AA]], i32* [[AA_C]], align
+// CHECK-32: store i32 [[AA]], i32* [[AA_CASTED]], align
+// CHECK: [[PARAM:%.+]] = load i[[SZ]], i[[SZ]]* [[AA_CASTED]], align
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]])* [[OMP_OUTLINED1:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[PARAM]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED1]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}})
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i32*
+// CHECK-64: [[AA:%.+]] = load i32, i32* [[AA_CADDR]], align
+// CHECK-32: [[AA:%.+]] = load i32, i32* [[AA_ADDR]], align
+// CHECK: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal void [[HVT2]](i[[SZ]] %{{.+}})
+// Create stack storage and store argument in there.
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK: [[AA:%.+]] = load i16, i16* [[AA_CADDR]], align
+// CHECK: [[AA_C:%.+]] = bitcast i[[SZ]]* [[AA_CASTED]] to i16*
+// CHECK: store i16 [[AA]], i16* [[AA_C]], align
+// CHECK: [[PARAM:%.+]] = load i[[SZ]], i[[SZ]]* [[AA_CASTED]], align
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]])* [[OMP_OUTLINED2:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[PARAM]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED2]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}})
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK: [[AA:%.+]] = load i16, i16* [[AA_CADDR]], align
+// CHECK: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal void [[HVT3]]
+// Create stack storage and store argument in there.
+// CHECK: [[A_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[A_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[A_ADDR]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64-DAG:[[A_CADDR:%.+]] = bitcast i[[SZ]]* [[A_ADDR]] to i32*
+// CHECK-DAG: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK-64-DAG:[[A:%.+]] = load i32, i32* [[A_CADDR]], align
+// CHECK-32-DAG:[[A:%.+]] = load i32, i32* [[A_ADDR]], align
+// CHECK-64-DAG:[[A_C:%.+]] = bitcast i[[SZ]]* [[A_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[A]], i32* [[A_C]], align
+// CHECK-32-DAG:store i32 [[A]], i32* [[A_CASTED]], align
+// CHECK-DAG: [[AA:%.+]] = load i16, i16* [[AA_CADDR]], align
+// CHECK-DAG: [[AA_C:%.+]] = bitcast i[[SZ]]* [[AA_CASTED]] to i16*
+// CHECK-DAG: store i16 [[AA]], i16* [[AA_C]], align
+// CHECK-DAG: [[PARAM1:%.+]] = load i[[SZ]], i[[SZ]]* [[A_CASTED]], align
+// CHECK-DAG: [[PARAM2:%.+]] = load i[[SZ]], i[[SZ]]* [[AA_CASTED]], align
+// CHECK-DAG: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], i[[SZ]])* [[OMP_OUTLINED3:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[PARAM1]], i[[SZ]] [[PARAM2]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED3]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}})
+// CHECK: [[A_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[A_ADDR]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64-DAG:[[A_CADDR:%.+]] = bitcast i[[SZ]]* [[A_ADDR]] to i32*
+// CHECK-DAG: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal void [[HVT4]]
+// Create local storage for each capture.
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x float]*
+// CHECK: [[LOCAL_VLA1:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_BN:%.+]] = alloca float*
+// CHECK: [[LOCAL_C:%.+]] = alloca [5 x [10 x double]]*
+// CHECK: [[LOCAL_VLA2:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA3:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_CN:%.+]] = alloca double*
+// CHECK: [[LOCAL_D:%.+]] = alloca [[TT]]*
+// CHECK: [[LOCAL_A_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
+// CHECK-DAG: store [10 x float]* [[ARG_B:%.+]], [10 x float]** [[LOCAL_B]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA1:%.+]], i[[SZ]]* [[LOCAL_VLA1]]
+// CHECK-DAG: store float* [[ARG_BN:%.+]], float** [[LOCAL_BN]]
+// CHECK-DAG: store [5 x [10 x double]]* [[ARG_C:%.+]], [5 x [10 x double]]** [[LOCAL_C]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA2:%.+]], i[[SZ]]* [[LOCAL_VLA2]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA3:%.+]], i[[SZ]]* [[LOCAL_VLA3]]
+// CHECK-DAG: store double* [[ARG_CN:%.+]], double** [[LOCAL_CN]]
+// CHECK-DAG: store [[TT]]* [[ARG_D:%.+]], [[TT]]** [[LOCAL_D]]
+
+// CHECK-64-DAG:[[CONV_AP:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
+// CHECK-DAG: [[REF_B:%.+]] = load [10 x float]*, [10 x float]** [[LOCAL_B]],
+// CHECK-DAG: [[VAL_VLA1:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA1]],
+// CHECK-DAG: [[REF_BN:%.+]] = load float*, float** [[LOCAL_BN]],
+// CHECK-DAG: [[REF_C:%.+]] = load [5 x [10 x double]]*, [5 x [10 x double]]** [[LOCAL_C]],
+// CHECK-DAG: [[VAL_VLA2:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA2]],
+// CHECK-DAG: [[VAL_VLA3:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA3]],
+// CHECK-DAG: [[REF_CN:%.+]] = load double*, double** [[LOCAL_CN]],
+// CHECK-DAG: [[REF_D:%.+]] = load [[TT]]*, [[TT]]** [[LOCAL_D]],
+
+// CHECK-64-DAG:[[CONV_A:%.+]] = load i32, i32* [[CONV_AP]]
+// CHECK-64-DAG:[[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_A_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[CONV_A]], i32* [[CONV]], align
+// CHECK-32-DAG:[[LOCAL_AV:%.+]] = load i32, i32* [[LOCAL_A]]
+// CHECK-32-DAG:store i32 [[LOCAL_AV]], i32* [[LOCAL_A_CASTED]], align
+// CHECK-DAG: [[REF_A:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_A_CASTED]],
+
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 9, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], [10 x float]*, i[[SZ]], float*, [5 x [10 x double]]*, i[[SZ]], i[[SZ]], double*, [[TT]]*)* [[OMP_OUTLINED4:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[REF_A]], [10 x float]* [[REF_B]], i[[SZ]] [[VAL_VLA1]], float* [[REF_BN]], [5 x [10 x double]]* [[REF_C]], i[[SZ]] [[VAL_VLA2]], i[[SZ]] [[VAL_VLA3]], double* [[REF_CN]], [[TT]]* [[REF_D]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED4]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, [10 x float]* {{.+}}, i[[SZ]] %{{.+}}, float* %{{.+}}, [5 x [10 x double]]* {{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, double* %{{.+}}, [[TT]]* {{.+}})
+// To reduce complexity, we're only going as far as validating the signature of the outlined parallel function.
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+ short aa = 0;
+ tx b[10];
+
+ #pragma omp target parallel if(target: n>40)
+ {
+ a += 1;
+ aa += 1;
+ b[2] += 1;
+ }
+
+ return a;
+}
+
+static
+int fstatic(int n) {
+ int a = 0;
+ short aa = 0;
+ char aaa = 0;
+ int b[10];
+
+ #pragma omp target parallel if(target: n>50)
+ {
+ a += 1;
+ aa += 1;
+ aaa += 1;
+ b[2] += 1;
+ }
+
+ return a;
+}
+
+struct S1 {
+ double a;
+
+ int r1(int n){
+ int b = n+1;
+ short int c[2][n];
+
+ #pragma omp target parallel if(target: n>60)
+ {
+ this->a = (double)b + 1.5;
+ c[1][1] = ++a;
+ }
+
+ return c[1][1] + (int)b;
+ }
+};
+
+// CHECK: define {{.*}}@{{.*}}bar{{.*}}
+int bar(int n){
+ int a = 0;
+
+ // CHECK: call {{.*}}i32 [[FOO]](i32 {{.*}})
+ a += foo(n);
+
+ S1 S;
+ // CHECK: call {{.*}}i32 [[FS1:@.+]]([[S1]]* {{.*}}, i32 {{.*}})
+ a += S.r1(n);
+
+ // CHECK: call {{.*}}i32 [[FSTATIC:@.+]](i32 {{.*}})
+ a += fstatic(n);
+
+ // CHECK: call {{.*}}i32 [[FTEMPLATE:@.+]](i32 {{.*}})
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+//
+// CHECK: define {{.*}}[[FS1]]
+//
+// CHECK: i8* @llvm.stacksave()
+// CHECK-64: [[B_ADDR:%.+]] = bitcast i[[SZ]]* [[B_CADDR:%.+]] to i32*
+// CHECK-64: store i32 %{{.+}}, i32* [[B_ADDR]],
+// CHECK-64: [[B_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[B_CADDR]],
+
+// CHECK-32: store i32 %{{.+}}, i32* [[B_ADDR:%.+]],
+// CHECK-32: [[B_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[B_ADDR]],
+
+// We capture 2 VLA sizes in this target region
+// CHECK: [[CELEMSIZE2:%.+]] = mul nuw i[[SZ]] 2, [[VLA0:%.+]]
+// CHECK: [[CSIZE:%.+]] = mul nuw i[[SZ]] [[CELEMSIZE2]], 2
+
+// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 60
+// CHECK: br i1 [[IF]], label %[[TRY:[^,]+]], label %[[FAIL:[^,]+]]
+// CHECK: [[TRY]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 5, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* [[SR:%[^,]+]], i32* getelementptr inbounds ([5 x i32], [5 x i32]* [[MAPT7]], i32 0, i32 0), i32 1, i32 0)
+// CHECK-DAG: [[BPR]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP:%.+]], i32 0, i32 0
+// CHECK-DAG: [[PR]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P:%.+]], i32 0, i32 0
+// CHECK-DAG: [[SR]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S:%.+]], i32 0, i32 0
+// CHECK-DAG: [[SADDR0:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 [[IDX0:[0-9]+]]
+// CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 [[IDX0]]
+// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 [[IDX0]]
+// CHECK-DAG: [[SADDR1:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 [[IDX1:[0-9]+]]
+// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 [[IDX1]]
+// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 [[IDX1]]
+// CHECK-DAG: [[SADDR2:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 [[IDX2:[0-9]+]]
+// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 [[IDX2]]
+// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 [[IDX2]]
+// CHECK-DAG: [[SADDR3:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 [[IDX3:[0-9]+]]
+// CHECK-DAG: [[BPADDR3:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 [[IDX3]]
+// CHECK-DAG: [[PADDR3:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 [[IDX3]]
+
+// The names below are not necessarily consistent with the names used for the
+// addresses above as some are repeated.
+// CHECK-DAG: [[BP0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+// CHECK-DAG: [[P0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+// CHECK-DAG: store i8* [[BP0]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* [[P0]], i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+// CHECK-DAG: store i8* inttoptr (i[[SZ]] 2 to i8*), i8** {{%[^,]+}}
+// CHECK-DAG: store i8* inttoptr (i[[SZ]] 2 to i8*), i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+// CHECK-DAG: [[BP2:%[^,]+]] = inttoptr i[[SZ]] [[B_CVAL]] to i8*
+// CHECK-DAG: [[P2:%[^,]+]] = inttoptr i[[SZ]] [[B_CVAL]] to i8*
+// CHECK-DAG: store i8* [[BP2]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* [[P2]], i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] 4, i[[SZ]]* {{%[^,]+}}
+
+// CHECK-DAG: [[BP3:%[^,]+]] = bitcast [[S1]]* %{{.+}} to i8*
+// CHECK-DAG: [[P3:%[^,]+]] = bitcast [[S1]]* %{{.+}} to i8*
+// CHECK-DAG: store i8* [[BP3]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* [[P3]], i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] 8, i[[SZ]]* {{%[^,]+}}
+
+// CHECK-DAG: [[BP4:%[^,]+]] = bitcast i16* %{{.+}} to i8*
+// CHECK-DAG: [[P4:%[^,]+]] = bitcast i16* %{{.+}} to i8*
+// CHECK-DAG: store i8* [[BP4]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* [[P4]], i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] [[CSIZE]], i[[SZ]]* {{%[^,]+}}
+
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT7:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[END]]
+// CHECK: [[END]]
+
+//
+// CHECK: define {{.*}}[[FSTATIC]]
+//
+// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 50
+// CHECK: br i1 [[IF]], label %[[IFTHEN:[^,]+]], label %[[IFELSE:[^,]+]]
+// CHECK: [[IFTHEN]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 4, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* getelementptr inbounds ([4 x i[[SZ]]], [4 x i[[SZ]]]* [[SIZET6]], i32 0, i32 0), i32* getelementptr inbounds ([4 x i32], [4 x i32]* [[MAPT6]], i32 0, i32 0), i32 1, i32 0)
+// CHECK-DAG: [[BPR]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP:%.+]], i32 0, i32 0
+// CHECK-DAG: [[PR]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P:%.+]], i32 0, i32 0
+
+// CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 0
+// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 0
+// CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
+// CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
+// CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] [[VAL0:%.+]] to i8*
+// CHECK-DAG: [[P0]] = inttoptr i[[SZ]] [[VAL0]] to i8*
+
+// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 1
+// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 1
+// CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
+// CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
+// CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] [[VAL1:%.+]] to i8*
+// CHECK-DAG: [[P1]] = inttoptr i[[SZ]] [[VAL1]] to i8*
+
+// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 2
+// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 2
+// CHECK-DAG: store i8* [[BP2:%[^,]+]], i8** [[BPADDR2]]
+// CHECK-DAG: store i8* [[P2:%[^,]+]], i8** [[PADDR2]]
+
+// CHECK-DAG: [[BPADDR3:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 3
+// CHECK-DAG: [[PADDR3:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 3
+// CHECK-DAG: store i8* [[BP3:%[^,]+]], i8** [[BPADDR3]]
+// CHECK-DAG: store i8* [[P3:%[^,]+]], i8** [[PADDR3]]
+// CHECK-DAG: [[BP3]] = bitcast [10 x i32]* %{{.+}} to i8*
+// CHECK-DAG: [[P3]] = bitcast [10 x i32]* %{{.+}} to i8*
+
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+// CHECK-NEXT: br label %[[IFEND:.+]]
+
+// CHECK: [[IFELSE]]
+// CHECK: store i32 -1, i32* [[RHV]], align 4
+// CHECK-NEXT: br label %[[IFEND:.+]]
+
+// CHECK: [[IFEND]]
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT6:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[END]]
+// CHECK: [[END]]
+
+//
+// CHECK: define {{.*}}[[FTEMPLATE]]
+//
+// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 40
+// CHECK: br i1 [[IF]], label %[[IFTHEN:[^,]+]], label %[[IFELSE:[^,]+]]
+// CHECK: [[IFTHEN]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* getelementptr inbounds ([3 x i[[SZ]]], [3 x i[[SZ]]]* [[SIZET5]], i32 0, i32 0), i32* getelementptr inbounds ([3 x i32], [3 x i32]* [[MAPT5]], i32 0, i32 0), i32 1, i32 0)
+// CHECK-DAG: [[BPR]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP:%.+]], i32 0, i32 0
+// CHECK-DAG: [[PR]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P:%.+]], i32 0, i32 0
+
+// CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP]], i32 0, i32 0
+// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 0
+// CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
+// CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
+// CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] [[VAL0:%.+]] to i8*
+// CHECK-DAG: [[P0]] = inttoptr i[[SZ]] [[VAL0]] to i8*
+
+// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP]], i32 0, i32 1
+// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 1
+// CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
+// CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
+// CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] [[VAL1:%.+]] to i8*
+// CHECK-DAG: [[P1]] = inttoptr i[[SZ]] [[VAL1]] to i8*
+
+// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP]], i32 0, i32 2
+// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 2
+// CHECK-DAG: store i8* [[BP2:%[^,]+]], i8** [[BPADDR2]]
+// CHECK-DAG: store i8* [[P2:%[^,]+]], i8** [[PADDR2]]
+// CHECK-DAG: [[BP2]] = bitcast [10 x i32]* %{{.+}} to i8*
+// CHECK-DAG: [[P2]] = bitcast [10 x i32]* %{{.+}} to i8*
+
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+// CHECK-NEXT: br label %[[IFEND:.+]]
+
+// CHECK: [[IFELSE]]
+// CHECK: store i32 -1, i32* [[RHV]], align 4
+// CHECK-NEXT: br label %[[IFEND:.+]]
+
+// CHECK: [[IFEND]]
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT5:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[END]]
+// CHECK: [[END]]
+
+
+
+// Check that the offloading functions are emitted and that the arguments are
+// correct and loaded correctly for the target regions of the callees of bar().
+
+// CHECK: define internal void [[HVT7]]
+// Create local storage for each capture.
+// CHECK: [[LOCAL_THIS:%.+]] = alloca [[S1]]*
+// CHECK: [[LOCAL_B:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA1:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA2:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_C:%.+]] = alloca i16*
+// CHECK: [[LOCAL_B_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK-DAG: store [[S1]]* [[ARG_THIS:%.+]], [[S1]]** [[LOCAL_THIS]]
+// CHECK-DAG: store i[[SZ]] [[ARG_B:%.+]], i[[SZ]]* [[LOCAL_B]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA1:%.+]], i[[SZ]]* [[LOCAL_VLA1]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA2:%.+]], i[[SZ]]* [[LOCAL_VLA2]]
+// CHECK-DAG: store i16* [[ARG_C:%.+]], i16** [[LOCAL_C]]
+// Store captures in the context.
+// CHECK-DAG: [[REF_THIS:%.+]] = load [[S1]]*, [[S1]]** [[LOCAL_THIS]],
+// CHECK-64-DAG:[[CONV_BP:%.+]] = bitcast i[[SZ]]* [[LOCAL_B]] to i32*
+// CHECK-DAG: [[VAL_VLA1:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA1]],
+// CHECK-DAG: [[VAL_VLA2:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA2]],
+// CHECK-DAG: [[REF_C:%.+]] = load i16*, i16** [[LOCAL_C]],
+
+// CHECK-64-DAG:[[CONV_B:%.+]] = load i32, i32* [[CONV_BP]]
+// CHECK-64-DAG:[[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_B_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[CONV_B]], i32* [[CONV]], align
+// CHECK-32-DAG:[[LOCAL_BV:%.+]] = load i32, i32* [[LOCAL_B]]
+// CHECK-32-DAG:store i32 [[LOCAL_BV]], i32* [[LOCAL_B_CASTED]], align
+// CHECK-DAG: [[REF_B:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_B_CASTED]],
+
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 5, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[S1]]*, i[[SZ]], i[[SZ]], i[[SZ]], i16*)* [[OMP_OUTLINED5:@.+]] to void (i32*, i32*, ...)*), [[S1]]* [[REF_THIS]], i[[SZ]] [[REF_B]], i[[SZ]] [[VAL_VLA1]], i[[SZ]] [[VAL_VLA2]], i16* [[REF_C]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED5]](i32* noalias %.global_tid., i32* noalias %.bound_tid., [[S1]]* %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i16* %{{.+}})
+// To reduce complexity, we're only going as far as validating the signature of the outlined parallel function.
+
+
+// CHECK: define internal void [[HVT6]]
+// Create local storage for each capture.
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AAA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x i32]*
+// CHECK: [[LOCAL_A_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AAA_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AA:%.+]], i[[SZ]]* [[LOCAL_AA]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AAA:%.+]], i[[SZ]]* [[LOCAL_AAA]]
+// CHECK-DAG: store [10 x i32]* [[ARG_B:%.+]], [10 x i32]** [[LOCAL_B]]
+// Store captures in the context.
+// CHECK-64-DAG:[[CONV_AP:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
+// CHECK-DAG: [[CONV_AAP:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA]] to i16*
+// CHECK-DAG: [[CONV_AAAP:%.+]] = bitcast i[[SZ]]* [[LOCAL_AAA]] to i8*
+// CHECK-DAG: [[REF_B:%.+]] = load [10 x i32]*, [10 x i32]** [[LOCAL_B]],
+
+// CHECK-64-DAG:[[CONV_A:%.+]] = load i32, i32* [[CONV_AP]]
+// CHECK-64-DAG:[[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_A_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[CONV_A]], i32* [[CONV]], align
+// CHECK-32-DAG:[[LOCAL_AV:%.+]] = load i32, i32* [[LOCAL_A]]
+// CHECK-32-DAG:store i32 [[LOCAL_AV]], i32* [[LOCAL_A_CASTED]], align
+// CHECK-DAG: [[REF_A:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_A_CASTED]],
+
+// CHECK-DAG: [[CONV_AA:%.+]] = load i16, i16* [[CONV_AAP]]
+// CHECK-DAG: [[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA_CASTED]] to i16*
+// CHECK-DAG: store i16 [[CONV_AA]], i16* [[CONV]], align
+// CHECK-DAG: [[REF_AA:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_AA_CASTED]],
+
+// CHECK-DAG: [[CONV_AAA:%.+]] = load i8, i8* [[CONV_AAAP]]
+// CHECK-DAG: [[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_AAA_CASTED]] to i8*
+// CHECK-DAG: store i8 [[CONV_AAA]], i8* [[CONV]], align
+// CHECK-DAG: [[REF_AAA:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_AAA_CASTED]],
+
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], i[[SZ]], i[[SZ]], [10 x i32]*)* [[OMP_OUTLINED6:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[REF_A]], i[[SZ]] [[REF_AA]], i[[SZ]] [[REF_AAA]], [10 x i32]* [[REF_B]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED6]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, [10 x i32]* {{.+}})
+// To reduce complexity, we're only going as far as validating the signature of the outlined parallel function.
+
+// CHECK: define internal void [[HVT5]]
+// Create local storage for each capture.
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x i32]*
+// CHECK: [[LOCAL_A_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AA:%.+]], i[[SZ]]* [[LOCAL_AA]]
+// CHECK-DAG: store [10 x i32]* [[ARG_B:%.+]], [10 x i32]** [[LOCAL_B]]
+// Store captures in the context.
+// CHECK-64-DAG:[[CONV_AP:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
+// CHECK-DAG: [[CONV_AAP:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA]] to i16*
+// CHECK-DAG: [[REF_B:%.+]] = load [10 x i32]*, [10 x i32]** [[LOCAL_B]],
+
+// CHECK-64-DAG:[[CONV_A:%.+]] = load i32, i32* [[CONV_AP]]
+// CHECK-64-DAG:[[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_A_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[CONV_A]], i32* [[CONV]], align
+// CHECK-32-DAG:[[LOCAL_AV:%.+]] = load i32, i32* [[LOCAL_A]]
+// CHECK-32-DAG:store i32 [[LOCAL_AV]], i32* [[LOCAL_A_CASTED]], align
+// CHECK-DAG: [[REF_A:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_A_CASTED]],
+
+// CHECK-DAG: [[CONV_AA:%.+]] = load i16, i16* [[CONV_AAP]]
+// CHECK-DAG: [[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA_CASTED]] to i16*
+// CHECK-DAG: store i16 [[CONV_AA]], i16* [[CONV]], align
+// CHECK-DAG: [[REF_AA:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_AA_CASTED]],
+
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], i[[SZ]], [10 x i32]*)* [[OMP_OUTLINED7:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[REF_A]], i[[SZ]] [[REF_AA]], [10 x i32]* [[REF_B]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED7]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, [10 x i32]* {{.+}})
+// To reduce complexity, we're only going as far as validating the signature of the outlined parallel function.
+
+#endif
diff --git a/test/OpenMP/target_parallel_codegen_registration.cpp b/test/OpenMP/target_parallel_codegen_registration.cpp
new file mode 100644
index 000000000000..6ba137ff10b6
--- /dev/null
+++ b/test/OpenMP/target_parallel_codegen_registration.cpp
@@ -0,0 +1,437 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+
+// Test target parallel codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+
+// Check that no target code is emmitted if no omptests flag was provided.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-NTARGET
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: [[SA:%.+]] = type { [4 x i32] }
+// CHECK-DAG: [[SB:%.+]] = type { [8 x i32] }
+// CHECK-DAG: [[SC:%.+]] = type { [16 x i32] }
+// CHECK-DAG: [[SD:%.+]] = type { [32 x i32] }
+// CHECK-DAG: [[SE:%.+]] = type { [64 x i32] }
+// CHECK-DAG: [[ST1:%.+]] = type { [228 x i32] }
+// CHECK-DAG: [[ST2:%.+]] = type { [1128 x i32] }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+
+// CHECK-DAG: [[A1:@.+]] = internal global [[SA]]
+// CHECK-DAG: [[A2:@.+]] = global [[SA]]
+// CHECK-DAG: [[B1:@.+]] = global [[SB]]
+// CHECK-DAG: [[B2:@.+]] = global [[SB]]
+// CHECK-DAG: [[C1:@.+]] = internal global [[SC]]
+// CHECK-DAG: [[D1:@.+]] = global [[SD]]
+// CHECK-DAG: [[E1:@.+]] = global [[SE]]
+// CHECK-DAG: [[T1:@.+]] = global [[ST1]]
+// CHECK-DAG: [[T2:@.+]] = global [[ST2]]
+
+// CHECK-NTARGET-DAG: [[SA:%.+]] = type { [4 x i32] }
+// CHECK-NTARGET-DAG: [[SB:%.+]] = type { [8 x i32] }
+// CHECK-NTARGET-DAG: [[SC:%.+]] = type { [16 x i32] }
+// CHECK-NTARGET-DAG: [[SD:%.+]] = type { [32 x i32] }
+// CHECK-NTARGET-DAG: [[SE:%.+]] = type { [64 x i32] }
+// CHECK-NTARGET-DAG: [[ST1:%.+]] = type { [228 x i32] }
+// CHECK-NTARGET-DAG: [[ST2:%.+]] = type { [1128 x i32] }
+// CHECK-NTARGET-NOT: type { i8*, i8*, %
+// CHECK-NTARGET-NOT: type { i32, %
+
+// We have 7 target regions
+
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// TCHECK-NOT: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+
+// CHECK-NTARGET-NOT: private constant i8 0
+// CHECK-NTARGET-NOT: private unnamed_addr constant [1 x i
+
+// CHECK-DAG: [[NAMEPTR1:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME1:__omp_offloading_[0-9a-f]+_[0-9a-f]+__Z.+_l[0-9]+]]\00"
+// CHECK-DAG: [[ENTRY1:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR1]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR2:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME2:.+]]\00"
+// CHECK-DAG: [[ENTRY2:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR2]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR3:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME3:.+]]\00"
+// CHECK-DAG: [[ENTRY3:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR3]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR4:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME4:.+]]\00"
+// CHECK-DAG: [[ENTRY4:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR4]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR5:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME5:.+]]\00"
+// CHECK-DAG: [[ENTRY5:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR5]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR6:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME6:.+]]\00"
+// CHECK-DAG: [[ENTRY6:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR6]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR7:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME7:.+]]\00"
+// CHECK-DAG: [[ENTRY7:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR7]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR8:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME8:.+]]\00"
+// CHECK-DAG: [[ENTRY8:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR8]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR9:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME9:.+]]\00"
+// CHECK-DAG: [[ENTRY9:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR9]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR10:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME10:.+]]\00"
+// CHECK-DAG: [[ENTRY10:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR10]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR11:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME11:.+]]\00"
+// CHECK-DAG: [[ENTRY11:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR11]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR12:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME12:.+]]\00"
+// CHECK-DAG: [[ENTRY12:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR12]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+
+// TCHECK-DAG: [[NAMEPTR1:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME1:__omp_offloading_[0-9a-f]+_[0-9a-f]+__Z.+_l[0-9]+]]\00"
+// TCHECK-DAG: [[ENTRY1:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR1]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR2:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME2:.+]]\00"
+// TCHECK-DAG: [[ENTRY2:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR2]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR3:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME3:.+]]\00"
+// TCHECK-DAG: [[ENTRY3:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR3]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR4:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME4:.+]]\00"
+// TCHECK-DAG: [[ENTRY4:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR4]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR5:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME5:.+]]\00"
+// TCHECK-DAG: [[ENTRY5:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR5]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR6:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME6:.+]]\00"
+// TCHECK-DAG: [[ENTRY6:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR6]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR7:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME7:.+]]\00"
+// TCHECK-DAG: [[ENTRY7:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR7]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR8:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME8:.+]]\00"
+// TCHECK-DAG: [[ENTRY8:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR8]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR9:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME9:.+]]\00"
+// TCHECK-DAG: [[ENTRY9:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR9]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR10:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME10:.+]]\00"
+// TCHECK-DAG: [[ENTRY10:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR10]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR11:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME11:.+]]\00"
+// TCHECK-DAG: [[ENTRY11:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR11]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR12:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME12:.+]]\00"
+// TCHECK-DAG: [[ENTRY12:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR12]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// We have 4 initializers, one for the 500 priority, another one for 501, or more for the default priority, and the last one for the offloading registration function.
+// CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [
+// CHECK-SAME: { i32, void ()*, i8* } { i32 500, void ()* [[P500:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 501, void ()* [[P501:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 65535, void ()* [[PMAX:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+// CHECK-NTARGET: @llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
+
+extern int *R;
+
+struct SA {
+ int arr[4];
+ void foo() {
+ int a = *R;
+ a += 1;
+ *R = a;
+ }
+ SA() {
+ int a = *R;
+ a += 2;
+ *R = a;
+ }
+ ~SA() {
+ int a = *R;
+ a += 3;
+ *R = a;
+ }
+};
+
+struct SB {
+ int arr[8];
+ void foo() {
+ int a = *R;
+ #pragma omp target parallel
+ a += 4;
+ *R = a;
+ }
+ SB() {
+ int a = *R;
+ a += 5;
+ *R = a;
+ }
+ ~SB() {
+ int a = *R;
+ a += 6;
+ *R = a;
+ }
+};
+
+struct SC {
+ int arr[16];
+ void foo() {
+ int a = *R;
+ a += 7;
+ *R = a;
+ }
+ SC() {
+ int a = *R;
+ #pragma omp target parallel
+ a += 8;
+ *R = a;
+ }
+ ~SC() {
+ int a = *R;
+ a += 9;
+ *R = a;
+ }
+};
+
+struct SD {
+ int arr[32];
+ void foo() {
+ int a = *R;
+ a += 10;
+ *R = a;
+ }
+ SD() {
+ int a = *R;
+ a += 11;
+ *R = a;
+ }
+ ~SD() {
+ int a = *R;
+ #pragma omp target parallel
+ a += 12;
+ *R = a;
+ }
+};
+
+struct SE {
+ int arr[64];
+ void foo() {
+ int a = *R;
+ #pragma omp target parallel if(target: 0)
+ a += 13;
+ *R = a;
+ }
+ SE() {
+ int a = *R;
+ #pragma omp target parallel
+ a += 14;
+ *R = a;
+ }
+ ~SE() {
+ int a = *R;
+ #pragma omp target parallel
+ a += 15;
+ *R = a;
+ }
+};
+
+template <int x>
+struct ST {
+ int arr[128 + x];
+ void foo() {
+ int a = *R;
+ #pragma omp target parallel
+ a += 16 + x;
+ *R = a;
+ }
+ ST() {
+ int a = *R;
+ #pragma omp target parallel
+ a += 17 + x;
+ *R = a;
+ }
+ ~ST() {
+ int a = *R;
+ #pragma omp target parallel
+ a += 18 + x;
+ *R = a;
+ }
+};
+
+// We have to make sure we us all the target regions:
+//CHECK-DAG: define internal void @[[NAME1]](
+//CHECK-DAG: call void @[[NAME1]](
+//CHECK-DAG: define internal void @[[NAME2]](
+//CHECK-DAG: call void @[[NAME2]](
+//CHECK-DAG: define internal void @[[NAME3]](
+//CHECK-DAG: call void @[[NAME3]](
+//CHECK-DAG: define internal void @[[NAME4]](
+//CHECK-DAG: call void @[[NAME4]](
+//CHECK-DAG: define internal void @[[NAME5]](
+//CHECK-DAG: call void @[[NAME5]](
+//CHECK-DAG: define internal void @[[NAME6]](
+//CHECK-DAG: call void @[[NAME6]](
+//CHECK-DAG: define internal void @[[NAME7]](
+//CHECK-DAG: call void @[[NAME7]](
+//CHECK-DAG: define internal void @[[NAME8]](
+//CHECK-DAG: call void @[[NAME8]](
+//CHECK-DAG: define internal void @[[NAME9]](
+//CHECK-DAG: call void @[[NAME9]](
+//CHECK-DAG: define internal void @[[NAME10]](
+//CHECK-DAG: call void @[[NAME10]](
+//CHECK-DAG: define internal void @[[NAME11]](
+//CHECK-DAG: call void @[[NAME11]](
+//CHECK-DAG: define internal void @[[NAME12]](
+//CHECK-DAG: call void @[[NAME12]](
+
+//TCHECK-DAG: define void @[[NAME1]](
+//TCHECK-DAG: define void @[[NAME2]](
+//TCHECK-DAG: define void @[[NAME3]](
+//TCHECK-DAG: define void @[[NAME4]](
+//TCHECK-DAG: define void @[[NAME5]](
+//TCHECK-DAG: define void @[[NAME6]](
+//TCHECK-DAG: define void @[[NAME7]](
+//TCHECK-DAG: define void @[[NAME8]](
+//TCHECK-DAG: define void @[[NAME9]](
+//TCHECK-DAG: define void @[[NAME10]](
+//TCHECK-DAG: define void @[[NAME11]](
+//TCHECK-DAG: define void @[[NAME12]](
+
+// CHECK-NTARGET-NOT: __tgt_target
+// CHECK-NTARGET-NOT: __tgt_register_lib
+// CHECK-NTARGET-NOT: __tgt_unregister_lib
+
+// TCHECK-NOT: __tgt_target
+// TCHECK-NOT: __tgt_register_lib
+// TCHECK-NOT: __tgt_unregister_lib
+
+// We have 2 initializers with priority 500
+//CHECK: define internal void [[P500]](
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// We have 1 initializers with priority 501
+//CHECK: define internal void [[P501]](
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// We have 6 initializers with default priority
+//CHECK: define internal void [[PMAX]](
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// Check registration and unregistration
+
+//CHECK: define internal void [[UNREGFN:@.+]](i8*)
+//CHECK: call i32 @__tgt_unregister_lib([[DSCTY]]* [[DESC]])
+//CHECK: ret void
+//CHECK: declare i32 @__tgt_unregister_lib([[DSCTY]]*)
+
+//CHECK: define internal void [[REGFN]](i8*)
+//CHECK: call i32 @__tgt_register_lib([[DSCTY]]* [[DESC]])
+//CHECK: call i32 @__cxa_atexit(void (i8*)* [[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
+//CHECK: ret void
+//CHECK: declare i32 @__tgt_register_lib([[DSCTY]]*)
+
+static __attribute__((init_priority(500))) SA a1;
+SA a2;
+SB __attribute__((init_priority(500))) b1;
+SB __attribute__((init_priority(501))) b2;
+static SC c1;
+SD d1;
+SE e1;
+ST<100> t1;
+ST<1000> t2;
+
+
+int bar(int a){
+ int r = a;
+
+ a1.foo();
+ a2.foo();
+ b1.foo();
+ b2.foo();
+ c1.foo();
+ d1.foo();
+ e1.foo();
+ t1.foo();
+ t2.foo();
+
+ #pragma omp target parallel
+ ++r;
+
+ return r + *R;
+}
+
+// Check metadata is properly generated:
+// CHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 193, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 243, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 259, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 265, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 276, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 282, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 402, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 288, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 282, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 288, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 276, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 218, i32 {{[0-9]+}}}
+
+// TCHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 193, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 243, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 259, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 265, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 276, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 282, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 402, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 288, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 282, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 288, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 276, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 218, i32 {{[0-9]+}}}
+
+#endif
diff --git a/test/OpenMP/target_parallel_codegen_registration_naming.cpp b/test/OpenMP/target_parallel_codegen_registration_naming.cpp
new file mode 100644
index 000000000000..4b7940290d07
--- /dev/null
+++ b/test/OpenMP/target_parallel_codegen_registration_naming.cpp
@@ -0,0 +1,66 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+
+// Test target parallel codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[CA:%.+]] = type { i32* }
+
+// CHECK: define {{.*}}i32 @[[NNAME:.+]](i32 {{.*}}%{{.+}})
+int nested(int a){
+ // CHECK: call void @__omp_offloading_[[FILEID:[0-9a-f]+_[0-9a-f]+]]_[[NNAME]]_l[[T1L:[0-9]+]](
+ #pragma omp target parallel
+ ++a;
+
+ // CHECK: call void @"[[LNAME:.+]]"([[CA]]*
+ auto F = [&](){
+ #pragma omp parallel
+ {
+ #pragma omp target parallel
+ ++a;
+ }
+ };
+
+ F();
+
+ return a;
+}
+
+// CHECK: define {{.*}}void @__omp_offloading_[[FILEID]]_[[NNAME]]_l[[T1L]](
+// TCHECK: define {{.*}}void @__omp_offloading_[[FILEID:[0-9a-f]+_[0-9a-f]+]]_[[NNAME:.+]]_l[[T1L:[0-9]+]](
+
+// CHECK: define {{.*}}void @"[[LNAME]]"(
+// CHECK: call void {{.*}}@__kmpc_fork_call{{.+}}[[PNAME:@.+]] to
+
+// CHECK: define {{.*}}void [[PNAME]](
+// CHECK: call void @__omp_offloading_[[FILEID]]_[[NNAME]]_l[[T2L:[0-9]+]](
+
+// CHECK: define {{.*}}void @__omp_offloading_[[FILEID]]_[[NNAME]]_l[[T2L]](
+// TCHECK: define {{.*}}void @__omp_offloading_[[FILEID]]_[[NNAME:.+]]_l[[T2L:[0-9]+]](
+
+
+// Check metadata is properly generated:
+// CHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 {{[0-9]+}}}
+
+// TCHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 {{[0-9]+}}}
+#endif
diff --git a/test/OpenMP/target_parallel_default_messages.cpp b/test/OpenMP/target_parallel_default_messages.cpp
index 40f31b84848a..cf497937f3e0 100644
--- a/test/OpenMP/target_parallel_default_messages.cpp
+++ b/test/OpenMP/target_parallel_default_messages.cpp
@@ -23,5 +23,8 @@ int main(int argc, char **argv) {
foo();
#pragma omp target parallel default(shared)
++argc;
+ #pragma omp target parallel default(none)
+ #pragma omp parallel default(shared)
+ ++argc;
return 0;
}
diff --git a/test/OpenMP/target_parallel_for_collapse_messages.cpp b/test/OpenMP/target_parallel_for_collapse_messages.cpp
index 8cf502be0d9c..6163b52fd21c 100644
--- a/test/OpenMP/target_parallel_for_collapse_messages.cpp
+++ b/test/OpenMP/target_parallel_for_collapse_messages.cpp
@@ -1,9 +1,14 @@
// RUN: %clang_cc1 -verify -fopenmp %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s
void foo() {
}
bool foobool(int argc) {
+#if __cplusplus >= 201103L
+// expected-note@-2 4 {{declared here}}
+#endif
return argc;
}
@@ -33,10 +38,17 @@ T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
// expected-error@+2 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp target parallel for collapse (foobool(argc)), collapse (true), collapse (-5)
+#if __cplusplus >= 201103L
+// expected-note@-2 2 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp target parallel for collapse (S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 2 {{expression is not an integral constant expression}}
+#if __cplusplus >= 201103L
+ // expected-error@+4 2 {{integral constant expression must have integral or unscoped enumeration type, not 'char *'}}
+#else
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+#endif
#pragma omp target parallel for collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp target parallel for collapse (1)
@@ -60,15 +72,25 @@ int main(int argc, char **argv) {
#pragma omp target parallel for collapse (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp target parallel for' are ignored}} expected-note {{as specified in 'collapse' clause}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; // expected-error {{expected 4 for loops after '#pragma omp target parallel for', but found only 1}}
#pragma omp target parallel for collapse (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
+#if __cplusplus >= 201103L
+// expected-note@-2 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp target parallel for' cannot contain more than one 'collapse' clause}}
// expected-error@+1 2 {{argument to 'collapse' clause must be a strictly positive integer value}}
#pragma omp target parallel for collapse (foobool(argc)), collapse (true), collapse (-5)
+#if __cplusplus >= 201103L
+// expected-note@-2 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp target parallel for collapse (S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
- // expected-error@+1 {{expression is not an integral constant expression}}
+#if __cplusplus >= 201103L
+ // expected-error@+4 {{integral constant expression must have integral or unscoped enumeration type, not 'char *'}}
+#else
+ // expected-error@+2 {{expression is not an integral constant expression}}
+#endif
#pragma omp target parallel for collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+3 {{statement after '#pragma omp target parallel for' must be a for loop}}
diff --git a/test/OpenMP/target_parallel_for_ordered_messages.cpp b/test/OpenMP/target_parallel_for_ordered_messages.cpp
index 36eb8371e025..72bb6e34912d 100644
--- a/test/OpenMP/target_parallel_for_ordered_messages.cpp
+++ b/test/OpenMP/target_parallel_for_ordered_messages.cpp
@@ -1,9 +1,14 @@
// RUN: %clang_cc1 -verify -fopenmp %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s
void foo() {
}
bool foobool(int argc) {
+#if __cplusplus >= 201103L
+// expected-note@-2 4 {{declared here}}
+#endif
return argc;
}
@@ -36,6 +41,9 @@ T tmain(T argc, S **argv) { //expected-note 2 {{declared here}
#pragma omp target parallel for ordered((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'ordered' clause}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp target parallel for', but found only 1}}
+#if __cplusplus >= 201103L
+// expected-note@+5 2 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
// expected-error@+3 2 {{directive '#pragma omp target parallel for' cannot contain more than one 'ordered' clause}}
// expected-error@+2 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
@@ -45,7 +53,11 @@ T tmain(T argc, S **argv) { //expected-note 2 {{declared here}
#pragma omp target parallel for ordered(S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
-// expected-error@+1 2 {{expression is not an integral constant expression}}
+#if __cplusplus >= 201103L
+ // expected-error@+4 2 {{integral constant expression must have integral or unscoped enumeration type, not 'char *'}}
+#else
+ // expected-error@+2 2 {{expression is not an integral constant expression}}
+#endif
#pragma omp target parallel for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
@@ -76,9 +88,15 @@ int main(int argc, char **argv) {
#pragma omp target parallel for ordered(2 + 2)) // expected-warning {{extra tokens at the end of '#pragma omp target parallel for' are ignored}} expected-note {{as specified in 'ordered' clause}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4]; // expected-error {{expected 4 for loops after '#pragma omp target parallel for', but found only 1}}
+#if __cplusplus >= 201103L
+// expected-note@+2 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
#pragma omp target parallel for ordered(foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
+#if __cplusplus >= 201103L
+// expected-note@+5 {{non-constexpr function 'foobool' cannot be used in a constant expression}}
+#endif
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp target parallel for' cannot contain more than one 'ordered' clause}}
// expected-error@+1 2 {{argument to 'ordered' clause must be a strictly positive integer value}}
@@ -88,7 +106,11 @@ int main(int argc, char **argv) {
#pragma omp target parallel for ordered(S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
-// expected-error@+1 {{expression is not an integral constant expression}}
+#if __cplusplus >= 201103L
+ // expected-error@+4 {{integral constant expression must have integral or unscoped enumeration type, not 'char *'}}
+#else
+ // expected-error@+2 {{expression is not an integral constant expression}}
+#endif
#pragma omp target parallel for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
diff --git a/test/OpenMP/target_parallel_if_codegen.cpp b/test/OpenMP/target_parallel_if_codegen.cpp
new file mode 100644
index 000000000000..02c69b95e19c
--- /dev/null
+++ b/test/OpenMP/target_parallel_if_codegen.cpp
@@ -0,0 +1,413 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: %ident_t = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[STR:@.+]] = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00"
+// CHECK-DAG: [[DEF_LOC:@.+]] = private unnamed_addr constant %ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
+
+// CHECK-DAG: [[S1:%.+]] = type { double }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+
+// We have 6 target regions
+
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+
+// Check if offloading descriptor is created.
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// Check target registration is registered as a Ctor.
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+
+ #pragma omp target parallel if(parallel: 0)
+ {
+ a += 1;
+ }
+
+ short b = 1;
+ #pragma omp target parallel if(parallel: 1)
+ {
+ a += b;
+ }
+
+ return a;
+}
+
+static
+int fstatic(int n) {
+
+ #pragma omp target parallel if(n>1)
+ {
+ }
+
+ #pragma omp target parallel if(target: n-2>2)
+ {
+ }
+
+ return n+1;
+}
+
+struct S1 {
+ double a;
+
+ int r1(int n){
+ int b = 1;
+
+ #pragma omp target parallel if(parallel: n>3)
+ {
+ this->a = (double)b + 1.5;
+ }
+
+ #pragma omp target parallel if(target: n>4) if(parallel: n>5)
+ {
+ this->a = 2.5;
+ }
+
+ return (int)a;
+ }
+};
+
+// CHECK: define {{.*}}@{{.*}}bar{{.*}}
+int bar(int n){
+ int a = 0;
+
+ S1 S;
+ // CHECK: call {{.*}}i32 [[FS1:@.+]]([[S1]]* {{.*}}, i32 {{.*}})
+ a += S.r1(n);
+
+ // CHECK: call {{.*}}i32 [[FSTATIC:@.+]](i32 {{.*}})
+ a += fstatic(n);
+
+ // CHECK: call {{.*}}i32 [[FTEMPLATE:@.+]](i32 {{.*}})
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+
+
+//
+// CHECK: define {{.*}}[[FS1]]([[S1]]* {{%.+}}, i32 {{[^%]*}}[[PARM:%.+]])
+//
+// CHECK-DAG: store i32 [[PARM]], i32* [[N_ADDR:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[CMP:%.+]] = icmp sgt i32 [[NV]], 3
+// CHECK: [[FB:%.+]] = zext i1 [[CMP]] to i8
+// CHECK: store i8 [[FB]], i8* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CAPE:%.+]] = load i8, i8* [[CAPE_ADDR]], align
+// CHECK: [[TB:%.+]] = trunc i8 [[CAPE]] to i1
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i8*
+// CHECK: [[FB:%.+]] = zext i1 [[TB]] to i8
+// CHECK: store i8 [[FB]], i8* [[CONV]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, {{.*}}, i32 1, i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT1:@.+]]([[S1]]* {{%.+}}, i[[SZ]] {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+//
+//
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[CMP:%.+]] = icmp sgt i32 [[NV]], 5
+// CHECK: [[FB:%.+]] = zext i1 [[CMP]] to i8
+// CHECK: store i8 [[FB]], i8* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CAPE:%.+]] = load i8, i8* [[CAPE_ADDR]], align
+// CHECK: [[TB:%.+]] = trunc i8 [[CAPE]] to i1
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i8*
+// CHECK: [[FB:%.+]] = zext i1 [[TB]] to i8
+// CHECK: store i8 [[FB]], i8* [[CONV]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[CMP:%.+]] = icmp sgt i32 [[NV]], 4
+// CHECK: br i1 [[CMP]], label {{%?}}[[IF_THEN:.+]], label {{%?}}[[IF_ELSE:.+]]
+//
+// CHECK: [[IF_THEN]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 2, {{.*}}, i32 1, i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: br label {{%?}}[[END:.+]]
+//
+// CHECK: [[IF_ELSE]]
+// CHECK: store i32 -1, i32* [[RHV]], align
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT2:@.+]]([[S1]]* {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+
+
+
+
+
+
+//
+// CHECK: define {{.*}}[[FSTATIC]](i32 {{[^%]*}}[[PARM:%.+]])
+//
+// CHECK-DAG: store i32 [[PARM]], i32* [[N_ADDR:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[CMP:%.+]] = icmp sgt i32 [[NV]], 1
+// CHECK: [[FB:%.+]] = zext i1 [[CMP]] to i8
+// CHECK: store i8 [[FB]], i8* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CAPE:%.+]] = load i8, i8* [[CAPE_ADDR]], align
+// CHECK: [[TB:%.+]] = trunc i8 [[CAPE]] to i1
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i8*
+// CHECK: [[FB:%.+]] = zext i1 [[TB]] to i8
+// CHECK: store i8 [[FB]], i8* [[CONV]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[CAPE2:%.+]] = load i8, i8* [[CAPE_ADDR]], align
+// CHECK: [[TB:%.+]] = trunc i8 [[CAPE2]] to i1
+// CHECK: br i1 [[TB]], label {{%?}}[[IF_THEN:.+]], label {{%?}}[[IF_ELSE:.+]]
+//
+// CHECK: [[IF_THEN]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.*}}, i32 1, i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: br label {{%?}}[[END:.+]]
+//
+// CHECK: [[IF_ELSE]]
+// CHECK: store i32 -1, i32* [[RHV]], align
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT3:@.+]](i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+//
+//
+// CHECK-DAG: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[SUB:%.+]] = sub nsw i32 [[NV]], 2
+// CHECK: [[CMP:%.+]] = icmp sgt i32 [[SUB]], 2
+// CHECK: br i1 [[CMP]], label {{%?}}[[IF_THEN:.+]], label {{%?}}[[IF_ELSE:.+]]
+//
+// CHECK: [[IF_THEN]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 0, {{.*}}, i32 1, i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: br label {{%?}}[[END:.+]]
+//
+// CHECK: [[IF_ELSE]]
+// CHECK: store i32 -1, i32* [[RHV]], align
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT4:@.+]]()
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+
+
+
+
+
+
+//
+// CHECK: define {{.*}}[[FTEMPLATE]]
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.*}}, i32 1, i32 0)
+// CHECK-NEXT: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK-NEXT: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT5:@.+]]({{[^,]+}})
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+//
+//
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 2, {{.*}}, i32 1, i32 0)
+// CHECK-NEXT: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK-NEXT: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT6:@.+]]({{[^,]+}}, {{[^,]+}})
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+
+
+
+
+
+
+// Check that the offloading functions are emitted and that the parallel function
+// is appropriately guarded.
+
+// CHECK: define internal void [[HVT1]]([[S1]]* {{%.+}}, i[[SZ]] [[PARM1:%.+]], i[[SZ]] [[PARM2:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM1]], i[[SZ]]* [[B_ADDR:%.+]], align
+// CHECK-DAG: store i[[SZ]] [[PARM2]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONVB:%.+]] = bitcast i[[SZ]]* [[B_ADDR]] to i32*
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i8*
+// CHECK-64: [[BV:%.+]] = load i32, i32* [[CONVB]], align
+// CHECK-32: [[BV:%.+]] = load i32, i32* [[B_ADDR]], align
+// CHECK-64: [[BC:%.+]] = bitcast i64* [[ARGA:%.+]] to i32*
+// CHECK-64: store i32 [[BV]], i32* [[BC]], align
+// CHECK-64: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[ARGA]], align
+// CHECK-32: store i32 [[BV]], i32* [[ARGA:%.+]], align
+// CHECK-32: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[ARGA]], align
+// CHECK: [[IFC:%.+]] = load i8, i8* [[CONV]], align
+// CHECK: [[TB:%.+]] = trunc i8 [[IFC]] to i1
+// CHECK: br i1 [[TB]], label {{%?}}[[IF_THEN:.+]], label {{%?}}[[IF_ELSE:.+]]
+//
+// CHECK: [[IF_THEN]]
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[S1]]*, i[[SZ]])* [[OMP_OUTLINED3:@.+]] to void (i32*, i32*, ...)*), [[S1]]* {{.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END:.+]]
+//
+// CHECK: [[IF_ELSE]]
+// CHECK: call void @__kmpc_serialized_parallel(
+// CHECK: call void [[OMP_OUTLINED3]](i32* {{%.+}}, i32* {{%.+}}, [[S1]]* {{.+}}, i[[SZ]] [[ARG]])
+// CHECK: call void @__kmpc_end_serialized_parallel(
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+//
+//
+
+
+// CHECK: define internal void [[HVT2]]([[S1]]* {{%.+}}, i[[SZ]] [[PARM:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i8*
+// CHECK: [[IFC:%.+]] = load i8, i8* [[CONV]], align
+// CHECK: [[TB:%.+]] = trunc i8 [[IFC]] to i1
+// CHECK: br i1 [[TB]], label {{%?}}[[IF_THEN:.+]], label {{%?}}[[IF_ELSE:.+]]
+//
+// CHECK: [[IF_THEN]]
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[S1]]*)* [[OMP_OUTLINED4:@.+]] to void (i32*, i32*, ...)*), [[S1]]* {{.+}})
+// CHECK: br label {{%?}}[[END:.+]]
+//
+// CHECK: [[IF_ELSE]]
+// CHECK: call void @__kmpc_serialized_parallel(
+// CHECK: call void [[OMP_OUTLINED4]](i32* {{%.+}}, i32* {{%.+}}, [[S1]]* {{.+}})
+// CHECK: call void @__kmpc_end_serialized_parallel(
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+//
+//
+
+
+
+
+
+
+
+
+// CHECK: define internal void [[HVT3]](i[[SZ]] [[PARM:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i8*
+// CHECK: [[IFC:%.+]] = load i8, i8* [[CONV]], align
+// CHECK: [[TB:%.+]] = trunc i8 [[IFC]] to i1
+// CHECK: br i1 [[TB]], label {{%?}}[[IF_THEN:.+]], label {{%?}}[[IF_ELSE:.+]]
+//
+// CHECK: [[IF_THEN]]
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* [[OMP_OUTLINED1:@.+]] to void (i32*, i32*, ...)*))
+// CHECK: br label {{%?}}[[END:.+]]
+//
+// CHECK: [[IF_ELSE]]
+// CHECK: call void @__kmpc_serialized_parallel(
+// CHECK: call void [[OMP_OUTLINED1]](i32* {{%.+}}, i32* {{%.+}})
+// CHECK: call void @__kmpc_end_serialized_parallel(
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+//
+//
+// CHECK: define internal void [[HVT4]]()
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* [[OMP_OUTLINED2:@.+]] to void (i32*, i32*, ...)*))
+// CHECK-NEXT: ret
+//
+//
+
+
+
+
+
+// CHECK: define internal void [[HVT5]](
+// CHECK-NOT: @__kmpc_fork_call
+// CHECK: call void @__kmpc_serialized_parallel(
+// CHECK: call void [[OMP_OUTLINED5:@.+]](i32* {{%.+}}, i32* {{%.+}}, i[[SZ]] {{.+}})
+// CHECK: call void @__kmpc_end_serialized_parallel(
+// CHECK: ret
+//
+//
+
+
+// CHECK: define internal void [[HVT6]](
+// CHECK-NOT: call void @__kmpc_serialized_parallel(
+// CHECK-NOT: call void [[OMP_OUTLINED5:@.+]](i32* {{%.+}}, i32* {{%.+}}, i[[SZ]] {{.+}})
+// CHECK-NOT: call void @__kmpc_end_serialized_parallel(
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], i[[SZ]])* [[OMP_OUTLINED5:@.+]] to void (i32*, i32*, ...)*),
+// CHECK: ret
+//
+//
+
+
+
+#endif
diff --git a/test/OpenMP/target_parallel_num_threads_codegen.cpp b/test/OpenMP/target_parallel_num_threads_codegen.cpp
new file mode 100644
index 000000000000..de6a13d087ab
--- /dev/null
+++ b/test/OpenMP/target_parallel_num_threads_codegen.cpp
@@ -0,0 +1,344 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: %ident_t = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[STR:@.+]] = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00"
+// CHECK-DAG: [[DEF_LOC:@.+]] = private unnamed_addr constant %ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
+
+// CHECK-DAG: [[S1:%.+]] = type { double }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+
+// We have 6 target regions
+
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+
+// Check if offloading descriptor is created.
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// Check target registration is registered as a Ctor.
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+
+ #pragma omp target parallel num_threads(tx(20))
+ {
+ }
+
+ short b = 1;
+ #pragma omp target parallel num_threads(b)
+ {
+ a += b;
+ }
+
+ return a;
+}
+
+static
+int fstatic(int n) {
+
+ #pragma omp target parallel num_threads(n)
+ {
+ }
+
+ #pragma omp target parallel num_threads(32+n)
+ {
+ }
+
+ return n+1;
+}
+
+struct S1 {
+ double a;
+
+ int r1(int n){
+ int b = 1;
+
+ #pragma omp target parallel num_threads(n-b)
+ {
+ this->a = (double)b + 1.5;
+ }
+
+ #pragma omp target parallel num_threads(1024)
+ {
+ this->a = 2.5;
+ }
+
+ return (int)a;
+ }
+};
+
+// CHECK: define {{.*}}@{{.*}}bar{{.*}}
+int bar(int n){
+ int a = 0;
+
+ S1 S;
+ // CHECK: call {{.*}}i32 [[FS1:@.+]]([[S1]]* {{.*}}, i32 {{.*}})
+ a += S.r1(n);
+
+ // CHECK: call {{.*}}i32 [[FSTATIC:@.+]](i32 {{.*}})
+ a += fstatic(n);
+
+ // CHECK: call {{.*}}i32 [[FTEMPLATE:@.+]](i32 {{.*}})
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+
+
+//
+// CHECK: define {{.*}}[[FS1]]([[S1]]* {{%.+}}, i32 {{[^%]*}}[[PARM:%.+]])
+//
+// CHECK-DAG: store i32 [[PARM]], i32* [[N_ADDR:%.+]], align
+// CHECK: store i32 1, i32* [[B:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[BV:%.+]] = load i32, i32* [[B]], align
+// CHECK: [[SUB:%.+]] = sub nsw i32 [[NV]], [[BV]]
+// CHECK: store i32 [[SUB]], i32* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR:%.+]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[THREADS:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, {{.*}}, i32 1, i32 [[THREADS]])
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT1:@.+]]([[S1]]* {{%.+}}, i[[SZ]] {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+//
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.+}}, i32 1, i32 1024)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT2:@.+]]([[S1]]* {{[^,]+}})
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+//
+// CHECK: define {{.*}}[[FSTATIC]](i32 {{[^%]*}}[[PARM:%.+]])
+//
+// CHECK-DAG: store i32 [[PARM]], i32* [[N_ADDR:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: store i32 [[NV]], i32* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR:%.+]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[THREADS:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.*}}, i32 1, i32 [[THREADS]])
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT3:@.+]](i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+//
+//
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[ADD:%.+]] = add nsw i32 32, [[NV]]
+// CHECK: store i32 [[ADD]], i32* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR:%.+]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[THREADS:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.*}}, i32 1, i32 [[THREADS]])
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT4:@.+]](i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+//
+// CHECK: define {{.*}}[[FTEMPLATE]]
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 0, {{.*}}, i32 1, i32 20)
+// CHECK-NEXT: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK-NEXT: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT5:@.+]]()
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+//
+//
+//
+// CHECK: store i16 1, i16* [[B:%.+]], align
+// CHECK: [[BV:%.+]] = load i16, i16* [[B]], align
+// CHECK: store i16 [[BV]], i16* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i16, i16* [[CAPE_ADDR]], align
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i16*
+// CHECK: store i16 [[CEV]], i16* [[CONV]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[T:%.+]] = load i16, i16* [[CAPE_ADDR]], align
+// CHECK: [[THREADS:%.+]] = sext i16 [[T]] to i32
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, {{.*}}, i32 1, i32 [[THREADS]])
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT6:@.+]](i[[SZ]] {{%.+}}, i[[SZ]] {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+// Check that the offloading functions are emitted and that the parallel function
+// is appropriately guarded.
+
+// CHECK: define internal void [[HVT1]]([[S1]]* {{%.+}}, i[[SZ]] [[PARM1:%.+]], i[[SZ]] [[PARM2:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM2]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i32*
+// CHECK-64: [[NT:%.+]] = load i32, i32* [[CONV]], align
+// CHECK-32: [[NT:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK: call void @__kmpc_push_num_threads(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]])
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 2,
+//
+//
+
+
+// CHECK: define internal void [[HVT2]]([[S1]]* {{%.+}})
+// CHECK: call void @__kmpc_push_num_threads(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 1024)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 1,
+//
+//
+
+
+
+
+
+
+
+
+// CHECK: define internal void [[HVT3]](i[[SZ]] [[PARM:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i32*
+// CHECK-64: [[NT:%.+]] = load i32, i32* [[CONV]], align
+// CHECK-32: [[NT:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK: call void @__kmpc_push_num_threads(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]])
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+// CHECK: define internal void [[HVT4]](i[[SZ]] [[PARM:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i32*
+// CHECK-64: [[NT:%.+]] = load i32, i32* [[CONV]], align
+// CHECK-32: [[NT:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK: call void @__kmpc_push_num_threads(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]])
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+
+
+
+
+
+// CHECK: define internal void [[HVT5]](
+// CHECK: call void @__kmpc_push_num_threads(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 20)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+
+
+// CHECK: define internal void [[HVT6]](i[[SZ]] [[PARM1:%.+]], i[[SZ]] [[PARM2:%.+]], i[[SZ]] [[PARM3:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM3]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i16*
+// CHECK: [[T:%.+]] = load i16, i16* [[CONV]], align
+// CHECK: [[NT:%.+]] = sext i16 [[T]] to i32
+// CHECK: call void @__kmpc_push_num_threads(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]])
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 2,
+//
+//
+
+
+
+#endif
diff --git a/test/OpenMP/target_teams_codegen.cpp b/test/OpenMP/target_teams_codegen.cpp
new file mode 100644
index 000000000000..6bac4e6e58c9
--- /dev/null
+++ b/test/OpenMP/target_teams_codegen.cpp
@@ -0,0 +1,802 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: %ident_t = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[STR:@.+]] = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00"
+// CHECK-DAG: [[DEF_LOC:@.+]] = private unnamed_addr constant %ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
+
+// CHECK-DAG: [[TT:%.+]] = type { i64, i8 }
+// CHECK-DAG: [[S1:%.+]] = type { double }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+
+// We have 8 target regions, but only 7 that actually will generate offloading
+// code, only 6 will have mapped arguments, and only 4 have all-constant map
+// sizes.
+
+// CHECK-DAG: [[SIZET2:@.+]] = private unnamed_addr constant [1 x i{{32|64}}] [i[[SZ:32|64]] 2]
+// CHECK-DAG: [[MAPT2:@.+]] = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: [[SIZET3:@.+]] = private unnamed_addr constant [2 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2]
+// CHECK-DAG: [[MAPT3:@.+]] = private unnamed_addr constant [2 x i32] [i32 288, i32 288]
+// CHECK-DAG: [[MAPT4:@.+]] = private unnamed_addr constant [9 x i32] [i32 288, i32 35, i32 288, i32 35, i32 35, i32 288, i32 288, i32 35, i32 35]
+// CHECK-DAG: [[SIZET5:@.+]] = private unnamed_addr constant [3 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2, i[[SZ]] 40]
+// CHECK-DAG: [[MAPT5:@.+]] = private unnamed_addr constant [3 x i32] [i32 288, i32 288, i32 35]
+// CHECK-DAG: [[SIZET6:@.+]] = private unnamed_addr constant [4 x i[[SZ]]] [i[[SZ]] 4, i[[SZ]] 2, i[[SZ]] 1, i[[SZ]] 40]
+// CHECK-DAG: [[MAPT6:@.+]] = private unnamed_addr constant [4 x i32] [i32 288, i32 288, i32 288, i32 35]
+// CHECK-DAG: [[MAPT7:@.+]] = private unnamed_addr constant [5 x i32] [i32 35, i32 288, i32 288, i32 288, i32 35]
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK-NOT: @{{.+}} = constant [[ENTTY]]
+
+// Check if offloading descriptor is created.
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// Check target registration is registered as a Ctor.
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+
+template<typename tx, typename ty>
+struct TT{
+ tx X;
+ ty Y;
+};
+
+// CHECK: define {{.*}}[[FOO:@.+]](
+int foo(int n) {
+ int a = 0;
+ short aa = 0;
+ float b[10];
+ float bn[n];
+ double c[5][10];
+ double cn[5][n];
+ TT<long long, char> d;
+
+ // CHECK: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 0, i8** null, i8** null, i[[SZ]]* null, i32* null, i32 0, i32 0)
+ // CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT0:@.+]]()
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target teams
+ {
+ }
+
+ // CHECK: store i32 0, i32* [[RHV:%.+]], align 4
+ // CHECK: store i32 -1, i32* [[RHV]], align 4
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK: call void [[HVT1:@.+]](i[[SZ]] {{[^,]+}})
+ #pragma omp target teams if(target: 0)
+ {
+ a += 1;
+ }
+
+ // CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, i8** [[BP:%[^,]+]], i8** [[P:%[^,]+]], i[[SZ]]* getelementptr inbounds ([1 x i[[SZ]]], [1 x i[[SZ]]]* [[SIZET2]], i32 0, i32 0), i32* getelementptr inbounds ([1 x i32], [1 x i32]* [[MAPT2]], i32 0, i32 0), i32 0, i32 0)
+ // CHECK-DAG: [[BP]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[BPR:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[P]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PR:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[BPR]], i32 0, i32 [[IDX0:[0-9]+]]
+ // CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PR]], i32 0, i32 [[IDX0]]
+ // CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
+ // CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
+ // CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+
+ // CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT2:@.+]](i[[SZ]] {{[^,]+}})
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target teams if(target: 1)
+ {
+ aa += 1;
+ }
+
+ // CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 10
+ // CHECK: br i1 [[IF]], label %[[IFTHEN:[^,]+]], label %[[IFELSE:[^,]+]]
+ // CHECK: [[IFTHEN]]
+ // CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 2, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* getelementptr inbounds ([2 x i[[SZ]]], [2 x i[[SZ]]]* [[SIZET3]], i32 0, i32 0), i32* getelementptr inbounds ([2 x i32], [2 x i32]* [[MAPT3]], i32 0, i32 0), i32 0, i32 0)
+ // CHECK-DAG: [[BPR]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BP:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[PR]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[P:%[^,]+]], i32 0, i32 0
+
+ // CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BP]], i32 0, i32 0
+ // CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[P]], i32 0, i32 0
+ // CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
+ // CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
+ // CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P0]] = inttoptr i[[SZ]] %{{.+}} to i8*
+
+ // CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BP]], i32 0, i32 1
+ // CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[P]], i32 0, i32 1
+ // CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
+ // CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
+ // CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK-DAG: [[P1]] = inttoptr i[[SZ]] %{{.+}} to i8*
+ // CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+ // CHECK-NEXT: br label %[[IFEND:.+]]
+
+ // CHECK: [[IFELSE]]
+ // CHECK: store i32 -1, i32* [[RHV]], align 4
+ // CHECK-NEXT: br label %[[IFEND:.+]]
+
+ // CHECK: [[IFEND]]
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT3:@.+]]({{[^,]+}}, {{[^,]+}})
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target teams if(target: n>10)
+ {
+ a += 1;
+ aa += 1;
+ }
+
+ // We capture 3 VLA sizes in this target region
+ // CHECK-64: [[A_VAL:%.+]] = load i32, i32* %{{.+}},
+ // CHECK-64: [[A_ADDR:%.+]] = bitcast i[[SZ]]* [[A_CADDR:%.+]] to i32*
+ // CHECK-64: store i32 [[A_VAL]], i32* [[A_ADDR]],
+ // CHECK-64: [[A_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[A_CADDR]],
+
+ // CHECK-32: [[A_VAL:%.+]] = load i32, i32* %{{.+}},
+ // CHECK-32: store i32 [[A_VAL]], i32* [[A_CADDR:%.+]],
+ // CHECK-32: [[A_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[A_CADDR]],
+
+ // CHECK: [[BNSIZE:%.+]] = mul nuw i[[SZ]] [[VLA0:%.+]], 4
+ // CHECK: [[CNELEMSIZE2:%.+]] = mul nuw i[[SZ]] 5, [[VLA1:%.+]]
+ // CHECK: [[CNSIZE:%.+]] = mul nuw i[[SZ]] [[CNELEMSIZE2]], 8
+
+ // CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 20
+ // CHECK: br i1 [[IF]], label %[[TRY:[^,]+]], label %[[FAIL:[^,]+]]
+ // CHECK: [[TRY]]
+ // CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 9, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* [[SR:%[^,]+]], i32* getelementptr inbounds ([9 x i32], [9 x i32]* [[MAPT4]], i32 0, i32 0), i32 0, i32 0)
+ // CHECK-DAG: [[BPR]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[PR]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P:%[^,]+]], i32 0, i32 0
+ // CHECK-DAG: [[SR]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S:%[^,]+]], i32 0, i32 0
+
+ // CHECK-DAG: [[SADDR0:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX0:[0-9]+]]
+ // CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX0]]
+ // CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX0]]
+ // CHECK-DAG: [[SADDR1:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX1:[0-9]+]]
+ // CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX1]]
+ // CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX1]]
+ // CHECK-DAG: [[SADDR2:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX2:[0-9]+]]
+ // CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX2]]
+ // CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX2]]
+ // CHECK-DAG: [[SADDR3:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX3:[0-9]+]]
+ // CHECK-DAG: [[BPADDR3:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX3]]
+ // CHECK-DAG: [[PADDR3:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX3]]
+ // CHECK-DAG: [[SADDR4:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX4:[0-9]+]]
+ // CHECK-DAG: [[BPADDR4:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX4]]
+ // CHECK-DAG: [[PADDR4:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX4]]
+ // CHECK-DAG: [[SADDR5:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX5:[0-9]+]]
+ // CHECK-DAG: [[BPADDR5:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX5]]
+ // CHECK-DAG: [[PADDR5:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX5]]
+ // CHECK-DAG: [[SADDR6:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX6:[0-9]+]]
+ // CHECK-DAG: [[BPADDR6:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX6]]
+ // CHECK-DAG: [[PADDR6:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX6]]
+ // CHECK-DAG: [[SADDR7:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX7:[0-9]+]]
+ // CHECK-DAG: [[BPADDR7:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX7]]
+ // CHECK-DAG: [[PADDR7:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX7]]
+ // CHECK-DAG: [[SADDR8:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX8:[0-9]+]]
+ // CHECK-DAG: [[BPADDR8:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BP]], i32 0, i32 [[IDX8]]
+ // CHECK-DAG: [[PADDR8:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[P]], i32 0, i32 [[IDX8]]
+
+ // The names below are not necessarily consistent with the names used for the
+ // addresses above as some are repeated.
+ // CHECK-DAG: [[BP0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+ // CHECK-DAG: [[P0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+ // CHECK-DAG: store i8* [[BP0]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P0]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP1:%[^,]+]] = inttoptr i[[SZ]] [[VLA1]] to i8*
+ // CHECK-DAG: [[P1:%[^,]+]] = inttoptr i[[SZ]] [[VLA1]] to i8*
+ // CHECK-DAG: store i8* [[BP1]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P1]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: store i8* inttoptr (i[[SZ]] 5 to i8*), i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* inttoptr (i[[SZ]] 5 to i8*), i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP3:%[^,]+]] = inttoptr i[[SZ]] [[A_CVAL]] to i8*
+ // CHECK-DAG: [[P3:%[^,]+]] = inttoptr i[[SZ]] [[A_CVAL]] to i8*
+ // CHECK-DAG: store i8* [[BP3]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P3]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] 4, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP4:%[^,]+]] = bitcast [10 x float]* %{{.+}} to i8*
+ // CHECK-DAG: [[P4:%[^,]+]] = bitcast [10 x float]* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP4]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P4]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] 40, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP5:%[^,]+]] = bitcast float* %{{.+}} to i8*
+ // CHECK-DAG: [[P5:%[^,]+]] = bitcast float* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP5]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P5]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] [[BNSIZE]], i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP6:%[^,]+]] = bitcast [5 x [10 x double]]* %{{.+}} to i8*
+ // CHECK-DAG: [[P6:%[^,]+]] = bitcast [5 x [10 x double]]* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP6]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P6]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] 400, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP7:%[^,]+]] = bitcast double* %{{.+}} to i8*
+ // CHECK-DAG: [[P7:%[^,]+]] = bitcast double* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP7]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P7]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] [[CNSIZE]], i[[SZ]]* {{%[^,]+}}
+
+ // CHECK-DAG: [[BP8:%[^,]+]] = bitcast [[TT]]* %{{.+}} to i8*
+ // CHECK-DAG: [[P8:%[^,]+]] = bitcast [[TT]]* %{{.+}} to i8*
+ // CHECK-DAG: store i8* [[BP8]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i8* [[P8]], i8** {{%[^,]+}}
+ // CHECK-DAG: store i[[SZ]] {{12|16}}, i[[SZ]]* {{%[^,]+}}
+
+ // CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+ // CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT4:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target teams if(target: n>20)
+ {
+ a += 1;
+ b[2] += 1.0;
+ bn[3] += 1.0;
+ c[1][2] += 1.0;
+ cn[1][3] += 1.0;
+ d.X += 1;
+ d.Y += 1;
+ }
+
+ return a;
+}
+
+// Check that the offloading functions are emitted and that the arguments are
+// correct and loaded correctly for the target regions in foo().
+
+// CHECK: define internal void [[HVT0]]()
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*))
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid.)
+// CHECK: ret void
+// CHECK-NEXT: }
+
+
+// CHECK: define internal void [[HVT1]](i[[SZ]] %{{.+}})
+// Create stack storage and store argument in there.
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i32*
+// CHECK-64: [[AA:%.+]] = load i32, i32* [[AA_CADDR]], align
+// CHECK-32: [[AA:%.+]] = load i32, i32* [[AA_ADDR]], align
+// CHECK-64: [[AA_C:%.+]] = bitcast i[[SZ]]* [[AA_CASTED]] to i32*
+// CHECK-64: store i32 [[AA]], i32* [[AA_C]], align
+// CHECK-32: store i32 [[AA]], i32* [[AA_CASTED]], align
+// CHECK: [[PARAM:%.+]] = load i[[SZ]], i[[SZ]]* [[AA_CASTED]], align
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]])* [[OMP_OUTLINED1:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[PARAM]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED1]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}})
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i32*
+// CHECK-64: [[AA:%.+]] = load i32, i32* [[AA_CADDR]], align
+// CHECK-32: [[AA:%.+]] = load i32, i32* [[AA_ADDR]], align
+// CHECK: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal void [[HVT2]](i[[SZ]] %{{.+}})
+// Create stack storage and store argument in there.
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK: [[AA:%.+]] = load i16, i16* [[AA_CADDR]], align
+// CHECK: [[AA_C:%.+]] = bitcast i[[SZ]]* [[AA_CASTED]] to i16*
+// CHECK: store i16 [[AA]], i16* [[AA_C]], align
+// CHECK: [[PARAM:%.+]] = load i[[SZ]], i[[SZ]]* [[AA_CASTED]], align
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]])* [[OMP_OUTLINED2:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[PARAM]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED2]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}})
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK: [[AA:%.+]] = load i16, i16* [[AA_CADDR]], align
+// CHECK: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal void [[HVT3]]
+// Create stack storage and store argument in there.
+// CHECK: [[A_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[A_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[A_ADDR]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64-DAG:[[A_CADDR:%.+]] = bitcast i[[SZ]]* [[A_ADDR]] to i32*
+// CHECK-DAG: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK-64-DAG:[[A:%.+]] = load i32, i32* [[A_CADDR]], align
+// CHECK-32-DAG:[[A:%.+]] = load i32, i32* [[A_ADDR]], align
+// CHECK-64-DAG:[[A_C:%.+]] = bitcast i[[SZ]]* [[A_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[A]], i32* [[A_C]], align
+// CHECK-32-DAG:store i32 [[A]], i32* [[A_CASTED]], align
+// CHECK-DAG: [[AA:%.+]] = load i16, i16* [[AA_CADDR]], align
+// CHECK-DAG: [[AA_C:%.+]] = bitcast i[[SZ]]* [[AA_CASTED]] to i16*
+// CHECK-DAG: store i16 [[AA]], i16* [[AA_C]], align
+// CHECK-DAG: [[PARAM1:%.+]] = load i[[SZ]], i[[SZ]]* [[A_CASTED]], align
+// CHECK-DAG: [[PARAM2:%.+]] = load i[[SZ]], i[[SZ]]* [[AA_CASTED]], align
+// CHECK-DAG: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], i[[SZ]])* [[OMP_OUTLINED3:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[PARAM1]], i[[SZ]] [[PARAM2]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED3]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}})
+// CHECK: [[A_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[A_ADDR]], align
+// CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[AA_ADDR]], align
+// CHECK-64-DAG:[[A_CADDR:%.+]] = bitcast i[[SZ]]* [[A_ADDR]] to i32*
+// CHECK-DAG: [[AA_CADDR:%.+]] = bitcast i[[SZ]]* [[AA_ADDR]] to i16*
+// CHECK: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal void [[HVT4]]
+// Create local storage for each capture.
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x float]*
+// CHECK: [[LOCAL_VLA1:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_BN:%.+]] = alloca float*
+// CHECK: [[LOCAL_C:%.+]] = alloca [5 x [10 x double]]*
+// CHECK: [[LOCAL_VLA2:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA3:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_CN:%.+]] = alloca double*
+// CHECK: [[LOCAL_D:%.+]] = alloca [[TT]]*
+// CHECK: [[LOCAL_A_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
+// CHECK-DAG: store [10 x float]* [[ARG_B:%.+]], [10 x float]** [[LOCAL_B]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA1:%.+]], i[[SZ]]* [[LOCAL_VLA1]]
+// CHECK-DAG: store float* [[ARG_BN:%.+]], float** [[LOCAL_BN]]
+// CHECK-DAG: store [5 x [10 x double]]* [[ARG_C:%.+]], [5 x [10 x double]]** [[LOCAL_C]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA2:%.+]], i[[SZ]]* [[LOCAL_VLA2]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA3:%.+]], i[[SZ]]* [[LOCAL_VLA3]]
+// CHECK-DAG: store double* [[ARG_CN:%.+]], double** [[LOCAL_CN]]
+// CHECK-DAG: store [[TT]]* [[ARG_D:%.+]], [[TT]]** [[LOCAL_D]]
+
+// CHECK-64-DAG:[[CONV_AP:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
+// CHECK-DAG: [[REF_B:%.+]] = load [10 x float]*, [10 x float]** [[LOCAL_B]],
+// CHECK-DAG: [[VAL_VLA1:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA1]],
+// CHECK-DAG: [[REF_BN:%.+]] = load float*, float** [[LOCAL_BN]],
+// CHECK-DAG: [[REF_C:%.+]] = load [5 x [10 x double]]*, [5 x [10 x double]]** [[LOCAL_C]],
+// CHECK-DAG: [[VAL_VLA2:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA2]],
+// CHECK-DAG: [[VAL_VLA3:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA3]],
+// CHECK-DAG: [[REF_CN:%.+]] = load double*, double** [[LOCAL_CN]],
+// CHECK-DAG: [[REF_D:%.+]] = load [[TT]]*, [[TT]]** [[LOCAL_D]],
+
+// CHECK-64-DAG:[[CONV_A:%.+]] = load i32, i32* [[CONV_AP]]
+// CHECK-64-DAG:[[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_A_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[CONV_A]], i32* [[CONV]], align
+// CHECK-32-DAG:[[LOCAL_AV:%.+]] = load i32, i32* [[LOCAL_A]]
+// CHECK-32-DAG:store i32 [[LOCAL_AV]], i32* [[LOCAL_A_CASTED]], align
+// CHECK-DAG: [[REF_A:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_A_CASTED]],
+
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 9, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], [10 x float]*, i[[SZ]], float*, [5 x [10 x double]]*, i[[SZ]], i[[SZ]], double*, [[TT]]*)* [[OMP_OUTLINED4:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[REF_A]], [10 x float]* [[REF_B]], i[[SZ]] [[VAL_VLA1]], float* [[REF_BN]], [5 x [10 x double]]* [[REF_C]], i[[SZ]] [[VAL_VLA2]], i[[SZ]] [[VAL_VLA3]], double* [[REF_CN]], [[TT]]* [[REF_D]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED4]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, [10 x float]* {{.+}}, i[[SZ]] %{{.+}}, float* %{{.+}}, [5 x [10 x double]]* {{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, double* %{{.+}}, [[TT]]* {{.+}})
+// To reduce complexity, we're only going as far as validating the signature of the outlined parallel function.
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+ short aa = 0;
+ tx b[10];
+
+ #pragma omp target teams if(target: n>40)
+ {
+ a += 1;
+ aa += 1;
+ b[2] += 1;
+ }
+
+ return a;
+}
+
+static
+int fstatic(int n) {
+ int a = 0;
+ short aa = 0;
+ char aaa = 0;
+ int b[10];
+
+ #pragma omp target teams if(target: n>50)
+ {
+ a += 1;
+ aa += 1;
+ aaa += 1;
+ b[2] += 1;
+ }
+
+ return a;
+}
+
+struct S1 {
+ double a;
+
+ int r1(int n){
+ int b = n+1;
+ short int c[2][n];
+
+ #pragma omp target teams if(target: n>60)
+ {
+ this->a = (double)b + 1.5;
+ c[1][1] = ++a;
+ }
+
+ return c[1][1] + (int)b;
+ }
+};
+
+// CHECK: define {{.*}}@{{.*}}bar{{.*}}
+int bar(int n){
+ int a = 0;
+
+ // CHECK: call {{.*}}i32 [[FOO]](i32 {{.*}})
+ a += foo(n);
+
+ S1 S;
+ // CHECK: call {{.*}}i32 [[FS1:@.+]]([[S1]]* {{.*}}, i32 {{.*}})
+ a += S.r1(n);
+
+ // CHECK: call {{.*}}i32 [[FSTATIC:@.+]](i32 {{.*}})
+ a += fstatic(n);
+
+ // CHECK: call {{.*}}i32 [[FTEMPLATE:@.+]](i32 {{.*}})
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+//
+// CHECK: define {{.*}}[[FS1]]
+//
+// CHECK: i8* @llvm.stacksave()
+// CHECK-64: [[B_ADDR:%.+]] = bitcast i[[SZ]]* [[B_CADDR:%.+]] to i32*
+// CHECK-64: store i32 %{{.+}}, i32* [[B_ADDR]],
+// CHECK-64: [[B_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[B_CADDR]],
+
+// CHECK-32: store i32 %{{.+}}, i32* [[B_ADDR:%.+]],
+// CHECK-32: [[B_CVAL:%.+]] = load i[[SZ]], i[[SZ]]* [[B_ADDR]],
+
+// We capture 2 VLA sizes in this target region
+// CHECK: [[CELEMSIZE2:%.+]] = mul nuw i[[SZ]] 2, [[VLA0:%.+]]
+// CHECK: [[CSIZE:%.+]] = mul nuw i[[SZ]] [[CELEMSIZE2]], 2
+
+// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 60
+// CHECK: br i1 [[IF]], label %[[TRY:[^,]+]], label %[[FAIL:[^,]+]]
+// CHECK: [[TRY]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 5, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* [[SR:%[^,]+]], i32* getelementptr inbounds ([5 x i32], [5 x i32]* [[MAPT7]], i32 0, i32 0), i32 0, i32 0)
+// CHECK-DAG: [[BPR]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP:%.+]], i32 0, i32 0
+// CHECK-DAG: [[PR]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P:%.+]], i32 0, i32 0
+// CHECK-DAG: [[SR]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S:%.+]], i32 0, i32 0
+// CHECK-DAG: [[SADDR0:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 [[IDX0:[0-9]+]]
+// CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 [[IDX0]]
+// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 [[IDX0]]
+// CHECK-DAG: [[SADDR1:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 [[IDX1:[0-9]+]]
+// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 [[IDX1]]
+// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 [[IDX1]]
+// CHECK-DAG: [[SADDR2:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 [[IDX2:[0-9]+]]
+// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 [[IDX2]]
+// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 [[IDX2]]
+// CHECK-DAG: [[SADDR3:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 [[IDX3:[0-9]+]]
+// CHECK-DAG: [[BPADDR3:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 [[IDX3]]
+// CHECK-DAG: [[PADDR3:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 [[IDX3]]
+
+// The names below are not necessarily consistent with the names used for the
+// addresses above as some are repeated.
+// CHECK-DAG: [[BP0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+// CHECK-DAG: [[P0:%[^,]+]] = inttoptr i[[SZ]] [[VLA0]] to i8*
+// CHECK-DAG: store i8* [[BP0]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* [[P0]], i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+// CHECK-DAG: store i8* inttoptr (i[[SZ]] 2 to i8*), i8** {{%[^,]+}}
+// CHECK-DAG: store i8* inttoptr (i[[SZ]] 2 to i8*), i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* {{%[^,]+}}
+
+// CHECK-DAG: [[BP2:%[^,]+]] = inttoptr i[[SZ]] [[B_CVAL]] to i8*
+// CHECK-DAG: [[P2:%[^,]+]] = inttoptr i[[SZ]] [[B_CVAL]] to i8*
+// CHECK-DAG: store i8* [[BP2]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* [[P2]], i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] 4, i[[SZ]]* {{%[^,]+}}
+
+// CHECK-DAG: [[BP3:%[^,]+]] = bitcast [[S1]]* %{{.+}} to i8*
+// CHECK-DAG: [[P3:%[^,]+]] = bitcast [[S1]]* %{{.+}} to i8*
+// CHECK-DAG: store i8* [[BP3]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* [[P3]], i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] 8, i[[SZ]]* {{%[^,]+}}
+
+// CHECK-DAG: [[BP4:%[^,]+]] = bitcast i16* %{{.+}} to i8*
+// CHECK-DAG: [[P4:%[^,]+]] = bitcast i16* %{{.+}} to i8*
+// CHECK-DAG: store i8* [[BP4]], i8** {{%[^,]+}}
+// CHECK-DAG: store i8* [[P4]], i8** {{%[^,]+}}
+// CHECK-DAG: store i[[SZ]] [[CSIZE]], i[[SZ]]* {{%[^,]+}}
+
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT7:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[END]]
+// CHECK: [[END]]
+
+//
+// CHECK: define {{.*}}[[FSTATIC]]
+//
+// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 50
+// CHECK: br i1 [[IF]], label %[[IFTHEN:[^,]+]], label %[[IFELSE:[^,]+]]
+// CHECK: [[IFTHEN]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 4, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* getelementptr inbounds ([4 x i[[SZ]]], [4 x i[[SZ]]]* [[SIZET6]], i32 0, i32 0), i32* getelementptr inbounds ([4 x i32], [4 x i32]* [[MAPT6]], i32 0, i32 0), i32 0, i32 0)
+// CHECK-DAG: [[BPR]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP:%.+]], i32 0, i32 0
+// CHECK-DAG: [[PR]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P:%.+]], i32 0, i32 0
+
+// CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 0
+// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 0
+// CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
+// CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
+// CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] [[VAL0:%.+]] to i8*
+// CHECK-DAG: [[P0]] = inttoptr i[[SZ]] [[VAL0]] to i8*
+
+// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 1
+// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 1
+// CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
+// CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
+// CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] [[VAL1:%.+]] to i8*
+// CHECK-DAG: [[P1]] = inttoptr i[[SZ]] [[VAL1]] to i8*
+
+// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 2
+// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 2
+// CHECK-DAG: store i8* [[BP2:%[^,]+]], i8** [[BPADDR2]]
+// CHECK-DAG: store i8* [[P2:%[^,]+]], i8** [[PADDR2]]
+
+// CHECK-DAG: [[BPADDR3:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BP]], i32 0, i32 3
+// CHECK-DAG: [[PADDR3:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[P]], i32 0, i32 3
+// CHECK-DAG: store i8* [[BP3:%[^,]+]], i8** [[BPADDR3]]
+// CHECK-DAG: store i8* [[P3:%[^,]+]], i8** [[PADDR3]]
+// CHECK-DAG: [[BP3]] = bitcast [10 x i32]* %{{.+}} to i8*
+// CHECK-DAG: [[P3]] = bitcast [10 x i32]* %{{.+}} to i8*
+
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+// CHECK-NEXT: br label %[[IFEND:.+]]
+
+// CHECK: [[IFELSE]]
+// CHECK: store i32 -1, i32* [[RHV]], align 4
+// CHECK-NEXT: br label %[[IFEND:.+]]
+
+// CHECK: [[IFEND]]
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT6:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[END]]
+// CHECK: [[END]]
+
+//
+// CHECK: define {{.*}}[[FTEMPLATE]]
+//
+// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 40
+// CHECK: br i1 [[IF]], label %[[IFTHEN:[^,]+]], label %[[IFELSE:[^,]+]]
+// CHECK: [[IFTHEN]]
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* getelementptr inbounds ([3 x i[[SZ]]], [3 x i[[SZ]]]* [[SIZET5]], i32 0, i32 0), i32* getelementptr inbounds ([3 x i32], [3 x i32]* [[MAPT5]], i32 0, i32 0), i32 0, i32 0)
+// CHECK-DAG: [[BPR]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP:%.+]], i32 0, i32 0
+// CHECK-DAG: [[PR]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P:%.+]], i32 0, i32 0
+
+// CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP]], i32 0, i32 0
+// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 0
+// CHECK-DAG: store i8* [[BP0:%[^,]+]], i8** [[BPADDR0]]
+// CHECK-DAG: store i8* [[P0:%[^,]+]], i8** [[PADDR0]]
+// CHECK-DAG: [[BP0]] = inttoptr i[[SZ]] [[VAL0:%.+]] to i8*
+// CHECK-DAG: [[P0]] = inttoptr i[[SZ]] [[VAL0]] to i8*
+
+// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP]], i32 0, i32 1
+// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 1
+// CHECK-DAG: store i8* [[BP1:%[^,]+]], i8** [[BPADDR1]]
+// CHECK-DAG: store i8* [[P1:%[^,]+]], i8** [[PADDR1]]
+// CHECK-DAG: [[BP1]] = inttoptr i[[SZ]] [[VAL1:%.+]] to i8*
+// CHECK-DAG: [[P1]] = inttoptr i[[SZ]] [[VAL1]] to i8*
+
+// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BP]], i32 0, i32 2
+// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[P]], i32 0, i32 2
+// CHECK-DAG: store i8* [[BP2:%[^,]+]], i8** [[BPADDR2]]
+// CHECK-DAG: store i8* [[P2:%[^,]+]], i8** [[PADDR2]]
+// CHECK-DAG: [[BP2]] = bitcast [10 x i32]* %{{.+}} to i8*
+// CHECK-DAG: [[P2]] = bitcast [10 x i32]* %{{.+}} to i8*
+
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align 4
+// CHECK-NEXT: br label %[[IFEND:.+]]
+
+// CHECK: [[IFELSE]]
+// CHECK: store i32 -1, i32* [[RHV]], align 4
+// CHECK-NEXT: br label %[[IFEND:.+]]
+
+// CHECK: [[IFEND]]
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT5:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[END]]
+// CHECK: [[END]]
+
+
+
+// Check that the offloading functions are emitted and that the arguments are
+// correct and loaded correctly for the target regions of the callees of bar().
+
+// CHECK: define internal void [[HVT7]]
+// Create local storage for each capture.
+// CHECK: [[LOCAL_THIS:%.+]] = alloca [[S1]]*
+// CHECK: [[LOCAL_B:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA1:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_VLA2:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_C:%.+]] = alloca i16*
+// CHECK: [[LOCAL_B_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK-DAG: store [[S1]]* [[ARG_THIS:%.+]], [[S1]]** [[LOCAL_THIS]]
+// CHECK-DAG: store i[[SZ]] [[ARG_B:%.+]], i[[SZ]]* [[LOCAL_B]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA1:%.+]], i[[SZ]]* [[LOCAL_VLA1]]
+// CHECK-DAG: store i[[SZ]] [[ARG_VLA2:%.+]], i[[SZ]]* [[LOCAL_VLA2]]
+// CHECK-DAG: store i16* [[ARG_C:%.+]], i16** [[LOCAL_C]]
+// Store captures in the context.
+// CHECK-DAG: [[REF_THIS:%.+]] = load [[S1]]*, [[S1]]** [[LOCAL_THIS]],
+// CHECK-64-DAG:[[CONV_BP:%.+]] = bitcast i[[SZ]]* [[LOCAL_B]] to i32*
+// CHECK-DAG: [[VAL_VLA1:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA1]],
+// CHECK-DAG: [[VAL_VLA2:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_VLA2]],
+// CHECK-DAG: [[REF_C:%.+]] = load i16*, i16** [[LOCAL_C]],
+
+// CHECK-64-DAG:[[CONV_B:%.+]] = load i32, i32* [[CONV_BP]]
+// CHECK-64-DAG:[[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_B_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[CONV_B]], i32* [[CONV]], align
+// CHECK-32-DAG:[[LOCAL_BV:%.+]] = load i32, i32* [[LOCAL_B]]
+// CHECK-32-DAG:store i32 [[LOCAL_BV]], i32* [[LOCAL_B_CASTED]], align
+// CHECK-DAG: [[REF_B:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_B_CASTED]],
+
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 5, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[S1]]*, i[[SZ]], i[[SZ]], i[[SZ]], i16*)* [[OMP_OUTLINED5:@.+]] to void (i32*, i32*, ...)*), [[S1]]* [[REF_THIS]], i[[SZ]] [[REF_B]], i[[SZ]] [[VAL_VLA1]], i[[SZ]] [[VAL_VLA2]], i16* [[REF_C]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED5]](i32* noalias %.global_tid., i32* noalias %.bound_tid., [[S1]]* %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i16* %{{.+}})
+// To reduce complexity, we're only going as far as validating the signature of the outlined parallel function.
+
+
+// CHECK: define internal void [[HVT6]]
+// Create local storage for each capture.
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AAA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x i32]*
+// CHECK: [[LOCAL_A_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AAA_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AA:%.+]], i[[SZ]]* [[LOCAL_AA]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AAA:%.+]], i[[SZ]]* [[LOCAL_AAA]]
+// CHECK-DAG: store [10 x i32]* [[ARG_B:%.+]], [10 x i32]** [[LOCAL_B]]
+// Store captures in the context.
+// CHECK-64-DAG:[[CONV_AP:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
+// CHECK-DAG: [[CONV_AAP:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA]] to i16*
+// CHECK-DAG: [[CONV_AAAP:%.+]] = bitcast i[[SZ]]* [[LOCAL_AAA]] to i8*
+// CHECK-DAG: [[REF_B:%.+]] = load [10 x i32]*, [10 x i32]** [[LOCAL_B]],
+
+// CHECK-64-DAG:[[CONV_A:%.+]] = load i32, i32* [[CONV_AP]]
+// CHECK-64-DAG:[[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_A_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[CONV_A]], i32* [[CONV]], align
+// CHECK-32-DAG:[[LOCAL_AV:%.+]] = load i32, i32* [[LOCAL_A]]
+// CHECK-32-DAG:store i32 [[LOCAL_AV]], i32* [[LOCAL_A_CASTED]], align
+// CHECK-DAG: [[REF_A:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_A_CASTED]],
+
+// CHECK-DAG: [[CONV_AA:%.+]] = load i16, i16* [[CONV_AAP]]
+// CHECK-DAG: [[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA_CASTED]] to i16*
+// CHECK-DAG: store i16 [[CONV_AA]], i16* [[CONV]], align
+// CHECK-DAG: [[REF_AA:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_AA_CASTED]],
+
+// CHECK-DAG: [[CONV_AAA:%.+]] = load i8, i8* [[CONV_AAAP]]
+// CHECK-DAG: [[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_AAA_CASTED]] to i8*
+// CHECK-DAG: store i8 [[CONV_AAA]], i8* [[CONV]], align
+// CHECK-DAG: [[REF_AAA:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_AAA_CASTED]],
+
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], i[[SZ]], i[[SZ]], [10 x i32]*)* [[OMP_OUTLINED6:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[REF_A]], i[[SZ]] [[REF_AA]], i[[SZ]] [[REF_AAA]], [10 x i32]* [[REF_B]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED6]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, [10 x i32]* {{.+}})
+// To reduce complexity, we're only going as far as validating the signature of the outlined parallel function.
+
+// CHECK: define internal void [[HVT5]]
+// Create local storage for each capture.
+// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_B:%.+]] = alloca [10 x i32]*
+// CHECK: [[LOCAL_A_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK: [[LOCAL_AA_CASTED:%.+]] = alloca i[[SZ]]
+// CHECK-DAG: store i[[SZ]] [[ARG_A:%.+]], i[[SZ]]* [[LOCAL_A]]
+// CHECK-DAG: store i[[SZ]] [[ARG_AA:%.+]], i[[SZ]]* [[LOCAL_AA]]
+// CHECK-DAG: store [10 x i32]* [[ARG_B:%.+]], [10 x i32]** [[LOCAL_B]]
+// Store captures in the context.
+// CHECK-64-DAG:[[CONV_AP:%.+]] = bitcast i[[SZ]]* [[LOCAL_A]] to i32*
+// CHECK-DAG: [[CONV_AAP:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA]] to i16*
+// CHECK-DAG: [[REF_B:%.+]] = load [10 x i32]*, [10 x i32]** [[LOCAL_B]],
+
+// CHECK-64-DAG:[[CONV_A:%.+]] = load i32, i32* [[CONV_AP]]
+// CHECK-64-DAG:[[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_A_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[CONV_A]], i32* [[CONV]], align
+// CHECK-32-DAG:[[LOCAL_AV:%.+]] = load i32, i32* [[LOCAL_A]]
+// CHECK-32-DAG:store i32 [[LOCAL_AV]], i32* [[LOCAL_A_CASTED]], align
+// CHECK-DAG: [[REF_A:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_A_CASTED]],
+
+// CHECK-DAG: [[CONV_AA:%.+]] = load i16, i16* [[CONV_AAP]]
+// CHECK-DAG: [[CONV:%.+]] = bitcast i[[SZ]]* [[LOCAL_AA_CASTED]] to i16*
+// CHECK-DAG: store i16 [[CONV_AA]], i16* [[CONV]], align
+// CHECK-DAG: [[REF_AA:%.+]] = load i[[SZ]], i[[SZ]]* [[LOCAL_AA_CASTED]],
+
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], i[[SZ]], [10 x i32]*)* [[OMP_OUTLINED7:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[REF_A]], i[[SZ]] [[REF_AA]], [10 x i32]* [[REF_B]])
+//
+//
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED7]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, [10 x i32]* {{.+}})
+// To reduce complexity, we're only going as far as validating the signature of the outlined parallel function.
+
+#endif
diff --git a/test/OpenMP/target_teams_codegen_registration.cpp b/test/OpenMP/target_teams_codegen_registration.cpp
new file mode 100644
index 000000000000..f65c701d7a66
--- /dev/null
+++ b/test/OpenMP/target_teams_codegen_registration.cpp
@@ -0,0 +1,437 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+
+// Test target teams codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+
+// Check that no target code is emmitted if no omptests flag was provided.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-NTARGET
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: [[SA:%.+]] = type { [4 x i32] }
+// CHECK-DAG: [[SB:%.+]] = type { [8 x i32] }
+// CHECK-DAG: [[SC:%.+]] = type { [16 x i32] }
+// CHECK-DAG: [[SD:%.+]] = type { [32 x i32] }
+// CHECK-DAG: [[SE:%.+]] = type { [64 x i32] }
+// CHECK-DAG: [[ST1:%.+]] = type { [228 x i32] }
+// CHECK-DAG: [[ST2:%.+]] = type { [1128 x i32] }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+
+// CHECK-DAG: [[A1:@.+]] = internal global [[SA]]
+// CHECK-DAG: [[A2:@.+]] = global [[SA]]
+// CHECK-DAG: [[B1:@.+]] = global [[SB]]
+// CHECK-DAG: [[B2:@.+]] = global [[SB]]
+// CHECK-DAG: [[C1:@.+]] = internal global [[SC]]
+// CHECK-DAG: [[D1:@.+]] = global [[SD]]
+// CHECK-DAG: [[E1:@.+]] = global [[SE]]
+// CHECK-DAG: [[T1:@.+]] = global [[ST1]]
+// CHECK-DAG: [[T2:@.+]] = global [[ST2]]
+
+// CHECK-NTARGET-DAG: [[SA:%.+]] = type { [4 x i32] }
+// CHECK-NTARGET-DAG: [[SB:%.+]] = type { [8 x i32] }
+// CHECK-NTARGET-DAG: [[SC:%.+]] = type { [16 x i32] }
+// CHECK-NTARGET-DAG: [[SD:%.+]] = type { [32 x i32] }
+// CHECK-NTARGET-DAG: [[SE:%.+]] = type { [64 x i32] }
+// CHECK-NTARGET-DAG: [[ST1:%.+]] = type { [228 x i32] }
+// CHECK-NTARGET-DAG: [[ST2:%.+]] = type { [1128 x i32] }
+// CHECK-NTARGET-NOT: type { i8*, i8*, %
+// CHECK-NTARGET-NOT: type { i32, %
+
+// We have 7 target regions
+
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// TCHECK-NOT: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+// CHECK-DAG: {{@.+}} = private constant i8 0
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i[[SZ]]] [i[[SZ]] 4]
+// CHECK-DAG: {{@.+}} = private unnamed_addr constant [1 x i32] [i32 288]
+
+// CHECK-NTARGET-NOT: private constant i8 0
+// CHECK-NTARGET-NOT: private unnamed_addr constant [1 x i
+
+// CHECK-DAG: [[NAMEPTR1:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME1:__omp_offloading_[0-9a-f]+_[0-9a-f]+__Z.+_l[0-9]+]]\00"
+// CHECK-DAG: [[ENTRY1:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR1]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR2:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME2:.+]]\00"
+// CHECK-DAG: [[ENTRY2:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR2]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR3:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME3:.+]]\00"
+// CHECK-DAG: [[ENTRY3:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR3]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR4:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME4:.+]]\00"
+// CHECK-DAG: [[ENTRY4:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR4]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR5:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME5:.+]]\00"
+// CHECK-DAG: [[ENTRY5:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR5]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR6:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME6:.+]]\00"
+// CHECK-DAG: [[ENTRY6:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR6]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR7:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME7:.+]]\00"
+// CHECK-DAG: [[ENTRY7:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR7]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR8:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME8:.+]]\00"
+// CHECK-DAG: [[ENTRY8:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR8]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR9:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME9:.+]]\00"
+// CHECK-DAG: [[ENTRY9:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR9]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR10:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME10:.+]]\00"
+// CHECK-DAG: [[ENTRY10:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR10]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR11:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME11:.+]]\00"
+// CHECK-DAG: [[ENTRY11:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR11]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// CHECK-DAG: [[NAMEPTR12:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME12:.+]]\00"
+// CHECK-DAG: [[ENTRY12:@.+]] = constant [[ENTTY]] { i8* @{{.*}}, i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR12]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+
+// TCHECK-DAG: [[NAMEPTR1:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME1:__omp_offloading_[0-9a-f]+_[0-9a-f]+__Z.+_l[0-9]+]]\00"
+// TCHECK-DAG: [[ENTRY1:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR1]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR2:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME2:.+]]\00"
+// TCHECK-DAG: [[ENTRY2:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR2]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR3:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME3:.+]]\00"
+// TCHECK-DAG: [[ENTRY3:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR3]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR4:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME4:.+]]\00"
+// TCHECK-DAG: [[ENTRY4:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR4]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR5:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME5:.+]]\00"
+// TCHECK-DAG: [[ENTRY5:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR5]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR6:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME6:.+]]\00"
+// TCHECK-DAG: [[ENTRY6:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR6]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR7:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME7:.+]]\00"
+// TCHECK-DAG: [[ENTRY7:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR7]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR8:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME8:.+]]\00"
+// TCHECK-DAG: [[ENTRY8:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR8]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR9:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME9:.+]]\00"
+// TCHECK-DAG: [[ENTRY9:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR9]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR10:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME10:.+]]\00"
+// TCHECK-DAG: [[ENTRY10:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR10]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR11:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME11:.+]]\00"
+// TCHECK-DAG: [[ENTRY11:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR11]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+// TCHECK-DAG: [[NAMEPTR12:@.+]] = internal unnamed_addr constant [{{.*}} x i8] c"[[NAME12:.+]]\00"
+// TCHECK-DAG: [[ENTRY12:@.+]] = constant [[ENTTY]] { i8* bitcast (void (i[[SZ]])* @{{.*}} to i8*), i8* getelementptr inbounds ([{{.*}} x i8], [{{.*}} x i8]* [[NAMEPTR12]], i32 0, i32 0), i[[SZ]] 0, i32 0, i32 0 }, section ".omp_offloading.entries", align 1
+
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// We have 4 initializers, one for the 500 priority, another one for 501, or more for the default priority, and the last one for the offloading registration function.
+// CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [
+// CHECK-SAME: { i32, void ()*, i8* } { i32 500, void ()* [[P500:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 501, void ()* [[P501:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 65535, void ()* [[PMAX:@[^,]+]], i8* null },
+// CHECK-SAME: { i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+// CHECK-NTARGET: @llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
+
+extern int *R;
+
+struct SA {
+ int arr[4];
+ void foo() {
+ int a = *R;
+ a += 1;
+ *R = a;
+ }
+ SA() {
+ int a = *R;
+ a += 2;
+ *R = a;
+ }
+ ~SA() {
+ int a = *R;
+ a += 3;
+ *R = a;
+ }
+};
+
+struct SB {
+ int arr[8];
+ void foo() {
+ int a = *R;
+ #pragma omp target teams
+ a += 4;
+ *R = a;
+ }
+ SB() {
+ int a = *R;
+ a += 5;
+ *R = a;
+ }
+ ~SB() {
+ int a = *R;
+ a += 6;
+ *R = a;
+ }
+};
+
+struct SC {
+ int arr[16];
+ void foo() {
+ int a = *R;
+ a += 7;
+ *R = a;
+ }
+ SC() {
+ int a = *R;
+ #pragma omp target teams
+ a += 8;
+ *R = a;
+ }
+ ~SC() {
+ int a = *R;
+ a += 9;
+ *R = a;
+ }
+};
+
+struct SD {
+ int arr[32];
+ void foo() {
+ int a = *R;
+ a += 10;
+ *R = a;
+ }
+ SD() {
+ int a = *R;
+ a += 11;
+ *R = a;
+ }
+ ~SD() {
+ int a = *R;
+ #pragma omp target teams
+ a += 12;
+ *R = a;
+ }
+};
+
+struct SE {
+ int arr[64];
+ void foo() {
+ int a = *R;
+ #pragma omp target teams if(target: 0)
+ a += 13;
+ *R = a;
+ }
+ SE() {
+ int a = *R;
+ #pragma omp target teams
+ a += 14;
+ *R = a;
+ }
+ ~SE() {
+ int a = *R;
+ #pragma omp target teams
+ a += 15;
+ *R = a;
+ }
+};
+
+template <int x>
+struct ST {
+ int arr[128 + x];
+ void foo() {
+ int a = *R;
+ #pragma omp target teams
+ a += 16 + x;
+ *R = a;
+ }
+ ST() {
+ int a = *R;
+ #pragma omp target teams
+ a += 17 + x;
+ *R = a;
+ }
+ ~ST() {
+ int a = *R;
+ #pragma omp target teams
+ a += 18 + x;
+ *R = a;
+ }
+};
+
+// We have to make sure we us all the target regions:
+//CHECK-DAG: define internal void @[[NAME1]](
+//CHECK-DAG: call void @[[NAME1]](
+//CHECK-DAG: define internal void @[[NAME2]](
+//CHECK-DAG: call void @[[NAME2]](
+//CHECK-DAG: define internal void @[[NAME3]](
+//CHECK-DAG: call void @[[NAME3]](
+//CHECK-DAG: define internal void @[[NAME4]](
+//CHECK-DAG: call void @[[NAME4]](
+//CHECK-DAG: define internal void @[[NAME5]](
+//CHECK-DAG: call void @[[NAME5]](
+//CHECK-DAG: define internal void @[[NAME6]](
+//CHECK-DAG: call void @[[NAME6]](
+//CHECK-DAG: define internal void @[[NAME7]](
+//CHECK-DAG: call void @[[NAME7]](
+//CHECK-DAG: define internal void @[[NAME8]](
+//CHECK-DAG: call void @[[NAME8]](
+//CHECK-DAG: define internal void @[[NAME9]](
+//CHECK-DAG: call void @[[NAME9]](
+//CHECK-DAG: define internal void @[[NAME10]](
+//CHECK-DAG: call void @[[NAME10]](
+//CHECK-DAG: define internal void @[[NAME11]](
+//CHECK-DAG: call void @[[NAME11]](
+//CHECK-DAG: define internal void @[[NAME12]](
+//CHECK-DAG: call void @[[NAME12]](
+
+//TCHECK-DAG: define void @[[NAME1]](
+//TCHECK-DAG: define void @[[NAME2]](
+//TCHECK-DAG: define void @[[NAME3]](
+//TCHECK-DAG: define void @[[NAME4]](
+//TCHECK-DAG: define void @[[NAME5]](
+//TCHECK-DAG: define void @[[NAME6]](
+//TCHECK-DAG: define void @[[NAME7]](
+//TCHECK-DAG: define void @[[NAME8]](
+//TCHECK-DAG: define void @[[NAME9]](
+//TCHECK-DAG: define void @[[NAME10]](
+//TCHECK-DAG: define void @[[NAME11]](
+//TCHECK-DAG: define void @[[NAME12]](
+
+// CHECK-NTARGET-NOT: __tgt_target
+// CHECK-NTARGET-NOT: __tgt_register_lib
+// CHECK-NTARGET-NOT: __tgt_unregister_lib
+
+// TCHECK-NOT: __tgt_target
+// TCHECK-NOT: __tgt_register_lib
+// TCHECK-NOT: __tgt_unregister_lib
+
+// We have 2 initializers with priority 500
+//CHECK: define internal void [[P500]](
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// We have 1 initializers with priority 501
+//CHECK: define internal void [[P501]](
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// We have 6 initializers with default priority
+//CHECK: define internal void [[PMAX]](
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK: call void @{{.+}}()
+//CHECK-NOT: call void @{{.+}}()
+//CHECK: ret void
+
+// Check registration and unregistration
+
+//CHECK: define internal void [[UNREGFN:@.+]](i8*)
+//CHECK: call i32 @__tgt_unregister_lib([[DSCTY]]* [[DESC]])
+//CHECK: ret void
+//CHECK: declare i32 @__tgt_unregister_lib([[DSCTY]]*)
+
+//CHECK: define internal void [[REGFN]](i8*)
+//CHECK: call i32 @__tgt_register_lib([[DSCTY]]* [[DESC]])
+//CHECK: call i32 @__cxa_atexit(void (i8*)* [[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
+//CHECK: ret void
+//CHECK: declare i32 @__tgt_register_lib([[DSCTY]]*)
+
+static __attribute__((init_priority(500))) SA a1;
+SA a2;
+SB __attribute__((init_priority(500))) b1;
+SB __attribute__((init_priority(501))) b2;
+static SC c1;
+SD d1;
+SE e1;
+ST<100> t1;
+ST<1000> t2;
+
+
+int bar(int a){
+ int r = a;
+
+ a1.foo();
+ a2.foo();
+ b1.foo();
+ b2.foo();
+ c1.foo();
+ d1.foo();
+ e1.foo();
+ t1.foo();
+ t2.foo();
+
+ #pragma omp target teams
+ ++r;
+
+ return r + *R;
+}
+
+// Check metadata is properly generated:
+// CHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 193, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 243, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 259, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 265, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 276, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 282, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 402, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 288, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 282, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 288, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 276, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 218, i32 {{[0-9]+}}}
+
+// TCHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 193, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 243, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 259, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 265, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 276, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 282, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 402, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 288, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 282, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 288, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 276, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 218, i32 {{[0-9]+}}}
+
+#endif
diff --git a/test/OpenMP/target_teams_codegen_registration_naming.cpp b/test/OpenMP/target_teams_codegen_registration_naming.cpp
new file mode 100644
index 000000000000..fb4232897282
--- /dev/null
+++ b/test/OpenMP/target_teams_codegen_registration_naming.cpp
@@ -0,0 +1,66 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+
+// Test target teams codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s -check-prefix=TCHECK
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -check-prefix=TCHECK
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[CA:%.+]] = type { i32* }
+
+// CHECK: define {{.*}}i32 @[[NNAME:.+]](i32 {{.*}}%{{.+}})
+int nested(int a){
+ // CHECK: call void @__omp_offloading_[[FILEID:[0-9a-f]+_[0-9a-f]+]]_[[NNAME]]_l[[T1L:[0-9]+]](
+ #pragma omp target teams
+ ++a;
+
+ // CHECK: call void @"[[LNAME:.+]]"([[CA]]*
+ auto F = [&](){
+ #pragma omp parallel
+ {
+ #pragma omp target teams
+ ++a;
+ }
+ };
+
+ F();
+
+ return a;
+}
+
+// CHECK: define {{.*}}void @__omp_offloading_[[FILEID]]_[[NNAME]]_l[[T1L]](
+// TCHECK: define {{.*}}void @__omp_offloading_[[FILEID:[0-9a-f]+_[0-9a-f]+]]_[[NNAME:.+]]_l[[T1L:[0-9]+]](
+
+// CHECK: define {{.*}}void @"[[LNAME]]"(
+// CHECK: call void {{.*}}@__kmpc_fork_call{{.+}}[[PNAME:@.+]] to
+
+// CHECK: define {{.*}}void [[PNAME]](
+// CHECK: call void @__omp_offloading_[[FILEID]]_[[NNAME]]_l[[T2L:[0-9]+]](
+
+// CHECK: define {{.*}}void @__omp_offloading_[[FILEID]]_[[NNAME]]_l[[T2L]](
+// TCHECK: define {{.*}}void @__omp_offloading_[[FILEID]]_[[NNAME:.+]]_l[[T2L:[0-9]+]](
+
+
+// Check metadata is properly generated:
+// CHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 {{[0-9]+}}}
+
+// TCHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 {{[0-9]+}}}
+#endif
diff --git a/test/OpenMP/target_teams_num_teams_codegen.cpp b/test/OpenMP/target_teams_num_teams_codegen.cpp
new file mode 100644
index 000000000000..6fcfa38e9bd3
--- /dev/null
+++ b/test/OpenMP/target_teams_num_teams_codegen.cpp
@@ -0,0 +1,344 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: %ident_t = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[STR:@.+]] = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00"
+// CHECK-DAG: [[DEF_LOC:@.+]] = private unnamed_addr constant %ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
+
+// CHECK-DAG: [[S1:%.+]] = type { double }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+
+// We have 6 target regions
+
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+
+// Check if offloading descriptor is created.
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// Check target registration is registered as a Ctor.
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+
+ #pragma omp target teams num_teams(tx(20))
+ {
+ }
+
+ short b = 1;
+ #pragma omp target teams num_teams(b)
+ {
+ a += b;
+ }
+
+ return a;
+}
+
+static
+int fstatic(int n) {
+
+ #pragma omp target teams num_teams(n)
+ {
+ }
+
+ #pragma omp target teams num_teams(32+n)
+ {
+ }
+
+ return n+1;
+}
+
+struct S1 {
+ double a;
+
+ int r1(int n){
+ int b = 1;
+
+ #pragma omp target teams num_teams(n-b)
+ {
+ this->a = (double)b + 1.5;
+ }
+
+ #pragma omp target teams num_teams(1024)
+ {
+ this->a = 2.5;
+ }
+
+ return (int)a;
+ }
+};
+
+// CHECK: define {{.*}}@{{.*}}bar{{.*}}
+int bar(int n){
+ int a = 0;
+
+ S1 S;
+ // CHECK: call {{.*}}i32 [[FS1:@.+]]([[S1]]* {{.*}}, i32 {{.*}})
+ a += S.r1(n);
+
+ // CHECK: call {{.*}}i32 [[FSTATIC:@.+]](i32 {{.*}})
+ a += fstatic(n);
+
+ // CHECK: call {{.*}}i32 [[FTEMPLATE:@.+]](i32 {{.*}})
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+
+
+//
+// CHECK: define {{.*}}[[FS1]]([[S1]]* {{%.+}}, i32 {{[^%]*}}[[PARM:%.+]])
+//
+// CHECK-DAG: store i32 [[PARM]], i32* [[N_ADDR:%.+]], align
+// CHECK: store i32 1, i32* [[B:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[BV:%.+]] = load i32, i32* [[B]], align
+// CHECK: [[SUB:%.+]] = sub nsw i32 [[NV]], [[BV]]
+// CHECK: store i32 [[SUB]], i32* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR:%.+]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[TEAMS:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, {{.*}}, i32 [[TEAMS]], i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT1:@.+]]([[S1]]* {{%.+}}, i[[SZ]] {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+//
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.+}}, i32 1024, i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT2:@.+]]([[S1]]* {{[^,]+}})
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+//
+// CHECK: define {{.*}}[[FSTATIC]](i32 {{[^%]*}}[[PARM:%.+]])
+//
+// CHECK-DAG: store i32 [[PARM]], i32* [[N_ADDR:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: store i32 [[NV]], i32* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR:%.+]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[TEAMS:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.*}}, i32 [[TEAMS]], i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT3:@.+]](i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+//
+//
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[ADD:%.+]] = add nsw i32 32, [[NV]]
+// CHECK: store i32 [[ADD]], i32* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR:%.+]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[TEAMS:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.*}}, i32 [[TEAMS]], i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT4:@.+]](i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+//
+// CHECK: define {{.*}}[[FTEMPLATE]]
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 0, {{.*}}, i32 20, i32 0)
+// CHECK-NEXT: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK-NEXT: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT5:@.+]]()
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+//
+//
+//
+// CHECK: store i16 1, i16* [[B:%.+]], align
+// CHECK: [[BV:%.+]] = load i16, i16* [[B]], align
+// CHECK: store i16 [[BV]], i16* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i16, i16* [[CAPE_ADDR]], align
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i16*
+// CHECK: store i16 [[CEV]], i16* [[CONV]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[T:%.+]] = load i16, i16* [[CAPE_ADDR]], align
+// CHECK: [[TEAMS:%.+]] = sext i16 [[T]] to i32
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, {{.*}}, i32 [[TEAMS]], i32 0)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT6:@.+]](i[[SZ]] {{%.+}}, i[[SZ]] {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+// Check that the offloading functions are emitted and that the parallel function
+// is appropriately guarded.
+
+// CHECK: define internal void [[HVT1]]([[S1]]* {{%.+}}, i[[SZ]] [[PARM1:%.+]], i[[SZ]] [[PARM2:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM2]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i32*
+// CHECK-64: [[NT:%.+]] = load i32, i32* [[CONV]], align
+// CHECK-32: [[NT:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]], i32 0)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 2,
+//
+//
+
+
+// CHECK: define internal void [[HVT2]]([[S1]]* {{%.+}})
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 1024, i32 0)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 1,
+//
+//
+
+
+
+
+
+
+
+
+// CHECK: define internal void [[HVT3]](i[[SZ]] [[PARM:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i32*
+// CHECK-64: [[NT:%.+]] = load i32, i32* [[CONV]], align
+// CHECK-32: [[NT:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]], i32 0)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+// CHECK: define internal void [[HVT4]](i[[SZ]] [[PARM:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i32*
+// CHECK-64: [[NT:%.+]] = load i32, i32* [[CONV]], align
+// CHECK-32: [[NT:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]], i32 0)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+
+
+
+
+
+// CHECK: define internal void [[HVT5]](
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 20, i32 0)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+
+
+// CHECK: define internal void [[HVT6]](i[[SZ]] [[PARM1:%.+]], i[[SZ]] [[PARM2:%.+]], i[[SZ]] [[PARM3:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM3]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i16*
+// CHECK: [[T:%.+]] = load i16, i16* [[CONV]], align
+// CHECK: [[NT:%.+]] = sext i16 [[T]] to i32
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]], i32 0)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 2,
+//
+//
+
+
+
+#endif
diff --git a/test/OpenMP/target_teams_thread_limit_codegen.cpp b/test/OpenMP/target_teams_thread_limit_codegen.cpp
new file mode 100644
index 000000000000..b2fe1bf60e6f
--- /dev/null
+++ b/test/OpenMP/target_teams_thread_limit_codegen.cpp
@@ -0,0 +1,357 @@
+// Test host codegen.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CHECK --check-prefix CHECK-32
+
+// Test target codegen - host bc file has to be created first.
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %s -o %t-x86-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -std=c++11 -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix TCHECK --check-prefix TCHECK-32
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK-DAG: %ident_t = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[STR:@.+]] = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00"
+// CHECK-DAG: [[DEF_LOC:@.+]] = private unnamed_addr constant %ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
+
+// CHECK-DAG: [[S1:%.+]] = type { double }
+// CHECK-DAG: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: [[DEVTY:%.+]] = type { i8*, i8*, [[ENTTY]]*, [[ENTTY]]* }
+// CHECK-DAG: [[DSCTY:%.+]] = type { i32, [[DEVTY]]*, [[ENTTY]]*, [[ENTTY]]* }
+
+// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+
+// We have 6 target regions
+
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+// CHECK-DAG: @{{.*}} = private constant i8 0
+
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = constant [[ENTTY]]
+
+// Check if offloading descriptor is created.
+// CHECK: [[ENTBEGIN:@.+]] = external constant [[ENTTY]]
+// CHECK: [[ENTEND:@.+]] = external constant [[ENTTY]]
+// CHECK: [[DEVBEGIN:@.+]] = external constant i8
+// CHECK: [[DEVEND:@.+]] = external constant i8
+// CHECK: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }]
+// CHECK: [[DESC:@.+]] = internal constant [[DSCTY]] { i32 1, [[DEVTY]]* getelementptr inbounds ([1 x [[DEVTY]]], [1 x [[DEVTY]]]* [[IMAGES]], i32 0, i32 0), [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }
+
+// Check target registration is registered as a Ctor.
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* [[REGFN:@.+]] to void ()*), i8* null }]
+
+
+template<typename tx>
+tx ftemplate(int n) {
+ tx a = 0;
+
+ #pragma omp target teams thread_limit(tx(20))
+ {
+ }
+
+ short b = 1;
+ #pragma omp target teams num_teams(b) thread_limit(1024)
+ {
+ a += b;
+ }
+
+ return a;
+}
+
+static
+int fstatic(int n) {
+
+ #pragma omp target teams num_teams(n) thread_limit(n*32)
+ {
+ }
+
+ #pragma omp target teams thread_limit(32+n)
+ {
+ }
+
+ return n+1;
+}
+
+struct S1 {
+ double a;
+
+ int r1(int n){
+ int b = 1;
+
+ #pragma omp target teams thread_limit(n-b)
+ {
+ this->a = (double)b + 1.5;
+ }
+
+ #pragma omp target teams thread_limit(1024)
+ {
+ this->a = 2.5;
+ }
+
+ return (int)a;
+ }
+};
+
+// CHECK: define {{.*}}@{{.*}}bar{{.*}}
+int bar(int n){
+ int a = 0;
+
+ S1 S;
+ // CHECK: call {{.*}}i32 [[FS1:@.+]]([[S1]]* {{.*}}, i32 {{.*}})
+ a += S.r1(n);
+
+ // CHECK: call {{.*}}i32 [[FSTATIC:@.+]](i32 {{.*}})
+ a += fstatic(n);
+
+ // CHECK: call {{.*}}i32 [[FTEMPLATE:@.+]](i32 {{.*}})
+ a += ftemplate<int>(n);
+
+ return a;
+}
+
+
+
+//
+// CHECK: define {{.*}}[[FS1]]([[S1]]* {{%.+}}, i32 {{[^%]*}}[[PARM:%.+]])
+//
+// CHECK-DAG: store i32 [[PARM]], i32* [[N_ADDR:%.+]], align
+// CHECK: store i32 1, i32* [[B:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[BV:%.+]] = load i32, i32* [[B]], align
+// CHECK: [[SUB:%.+]] = sub nsw i32 [[NV]], [[BV]]
+// CHECK: store i32 [[SUB]], i32* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR:%.+]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[TL:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, {{.*}}, i32 0, i32 [[TL]])
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT1:@.+]]([[S1]]* {{%.+}}, i[[SZ]] {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+//
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.+}}, i32 0, i32 1024)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT2:@.+]]([[S1]]* {{[^,]+}})
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+//
+// CHECK: define {{.*}}[[FSTATIC]](i32 {{[^%]*}}[[PARM:%.+]])
+//
+// CHECK-DAG: store i32 [[PARM]], i32* [[N_ADDR:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: store i32 [[NV]], i32* [[CAPE_ADDR1:%.+]], align
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[MUL:%.+]] = mul nsw i32 [[NV]], 32
+// CHECK: store i32 [[MUL]], i32* [[CAPE_ADDR2:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR1]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR1:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR1:%.+]], align
+// CHECK: [[ARG1:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR1]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR2]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR2:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR2:%.+]], align
+// CHECK: [[ARG2:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR2]], align
+// CHECK: [[TEAMS:%.+]] = load i32, i32* [[CAPE_ADDR1]], align
+// CHECK: [[TL:%.+]] = load i32, i32* [[CAPE_ADDR2]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 2, {{.*}}, i32 [[TEAMS]], i32 [[TL]])
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT3:@.+]](i[[SZ]] [[ARG1]], i[[SZ]] [[ARG2]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+//
+//
+// CHECK: [[NV:%.+]] = load i32, i32* [[N_ADDR]], align
+// CHECK: [[ADD:%.+]] = add nsw i32 32, [[NV]]
+// CHECK: store i32 [[ADD]], i32* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i32*
+// CHECK-64: store i32 [[CEV]], i32* [[CONV]], align
+// CHECK-32: store i32 [[CEV]], i32* [[CAPEC_ADDR:%.+]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[TL:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 1, {{.*}}, i32 0, i32 [[TL]])
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT4:@.+]](i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+//
+// CHECK: define {{.*}}[[FTEMPLATE]]
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 0, {{.*}}, i32 0, i32 20)
+// CHECK-NEXT: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK-NEXT: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT5:@.+]]()
+// CHECK: br label {{%?}}[[END]]
+//
+// CHECK: [[END]]
+//
+//
+//
+// CHECK: store i16 1, i16* [[B:%.+]], align
+// CHECK: [[BV:%.+]] = load i16, i16* [[B]], align
+// CHECK: store i16 [[BV]], i16* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CEV:%.+]] = load i16, i16* [[CAPE_ADDR]], align
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPEC_ADDR:%.+]] to i16*
+// CHECK: store i16 [[CEV]], i16* [[CONV]], align
+// CHECK: [[ARG:%.+]] = load i[[SZ]], i[[SZ]]* [[CAPEC_ADDR]], align
+// CHECK: [[T:%.+]] = load i16, i16* [[CAPE_ADDR]], align
+// CHECK: [[TEAMS:%.+]] = sext i16 [[T]] to i32
+//
+// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target_teams(i32 -1, i8* @{{[^,]+}}, i32 3, {{.*}}, i32 [[TEAMS]], i32 1024)
+// CHECK: store i32 [[RET]], i32* [[RHV:%.+]], align
+// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
+//
+// CHECK: [[FAIL]]
+// CHECK: call void [[HVT6:@.+]](i[[SZ]] {{%.+}}, i[[SZ]] {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK: br label {{%?}}[[END]]
+// CHECK: [[END]]
+//
+
+
+
+
+
+
+// Check that the offloading functions are emitted and that the parallel function
+// is appropriately guarded.
+
+// CHECK: define internal void [[HVT1]]([[S1]]* {{%.+}}, i[[SZ]] [[PARM1:%.+]], i[[SZ]] [[PARM2:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM2]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i32*
+// CHECK-64: [[TL:%.+]] = load i32, i32* [[CONV]], align
+// CHECK-32: [[TL:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 0, i32 [[TL]])
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 2,
+//
+//
+
+
+// CHECK: define internal void [[HVT2]]([[S1]]* {{%.+}})
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 0, i32 1024)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 1,
+//
+//
+
+
+
+
+
+
+
+
+// CHECK: define internal void [[HVT3]](i[[SZ]] [[PARM1:%.+]], i[[SZ]] [[PARM2:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM1]], i[[SZ]]* [[CAPE_ADDR1:%.+]], align
+// CHECK-DAG: store i[[SZ]] [[PARM2]], i[[SZ]]* [[CAPE_ADDR2:%.+]], align
+// CHECK-64: [[CONV1:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR1]] to i32*
+// CHECK-64: [[CONV2:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR2]] to i32*
+// CHECK-64: [[NT:%.+]] = load i32, i32* [[CONV1]], align
+// CHECK-64: [[TL:%.+]] = load i32, i32* [[CONV2]], align
+// CHECK-32: [[NT:%.+]] = load i32, i32* [[CAPE_ADDR1]], align
+// CHECK-32: [[TL:%.+]] = load i32, i32* [[CAPE_ADDR2]], align
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]], i32 [[TL]])
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+// CHECK: define internal void [[HVT4]](i[[SZ]] [[PARM:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK-64: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i32*
+// CHECK-64: [[TL:%.+]] = load i32, i32* [[CONV]], align
+// CHECK-32: [[TL:%.+]] = load i32, i32* [[CAPE_ADDR]], align
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 0, i32 [[TL]])
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+
+
+
+
+
+// CHECK: define internal void [[HVT5]](
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 0, i32 20)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 0,
+//
+//
+
+
+// CHECK: define internal void [[HVT6]](i[[SZ]] [[PARM1:%.+]], i[[SZ]] [[PARM2:%.+]], i[[SZ]] [[PARM3:%.+]])
+// CHECK-DAG: store i[[SZ]] [[PARM3]], i[[SZ]]* [[CAPE_ADDR:%.+]], align
+// CHECK: [[CONV:%.+]] = bitcast i[[SZ]]* [[CAPE_ADDR]] to i16*
+// CHECK: [[T:%.+]] = load i16, i16* [[CONV]], align
+// CHECK: [[NT:%.+]] = sext i16 [[T]] to i32
+// CHECK: call i32 @__kmpc_push_num_teams(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 [[NT]], i32 1024)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 2,
+//
+//
+
+
+
+#endif
diff --git a/test/OpenMP/threadprivate_codegen.cpp b/test/OpenMP/threadprivate_codegen.cpp
index 318415761ac7..3785b70c19ba 100644
--- a/test/OpenMP/threadprivate_codegen.cpp
+++ b/test/OpenMP/threadprivate_codegen.cpp
@@ -176,7 +176,7 @@ struct S5 {
// CHECK-TLS-DAG: [[ST_S4_ST:@.+]] = linkonce_odr thread_local global %struct.S4 zeroinitializer
// CHECK-TLS-DAG: [[ST_S4_ST_GUARD:@_ZGVN2STI2S4E2stE]] = linkonce_odr thread_local global i64 0
// CHECK-TLS-DAG: @__tls_guard = internal thread_local global i8 0
-// CHECK-TLS-DAG: @__dso_handle = external global i8
+// CHECK-TLS-DAG: @__dso_handle = external hidden global i8
// CHECK-TLS-DAG: [[GS1_TLS_INIT:@_ZTHL3gs1]] = internal alias void (), void ()* @__tls_init
// CHECK-TLS-DAG: [[ARR_X_TLS_INIT:@_ZTH5arr_x]] = alias void (), void ()* @__tls_init
diff --git a/test/OpenMP/vla_crash.c b/test/OpenMP/vla_crash.c
new file mode 100644
index 000000000000..50dcf068707b
--- /dev/null
+++ b/test/OpenMP/vla_crash.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -verify -triple powerpc64le-unknown-linux-gnu -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+int a;
+
+// CHECK-LABEL: foo
+void foo() {
+ int(*b)[a];
+ int *(**c)[a];
+ // CHECK: [[B:%.+]] = alloca i32*,
+ // CHECK: [[C:%.+]] = alloca i32***,
+ // CHECK: @__kmpc_global_thread_num
+ // CHECK: call void @__kmpc_serialized_parallel
+ // CHECK: call void [[OUTLINED:@[^(]+]](i32* %{{[^,]+}}, i32* %{{[^,]+}}, i64 %{{[^,]+}}, i32** [[B]], i64 %{{[^,]+}}, i32**** [[C]])
+ // CHECK: call void @__kmpc_end_serialized_parallel
+ // CHECK: ret void
+#pragma omp parallel if (0)
+ b[0][0] = c[0][a][0][a];
+}
+
+// CHECK: define internal void [[OUTLINED]](i32* {{[^,]+}}, i32* {{[^,]+}}, i64 {{[^,]+}}, i32** {{[^,]+}}, i64 {{[^,]+}}, i32**** {{[^,]+}})
+
diff --git a/test/PCH/cxx-dependent-sized-ext-vector.cpp b/test/PCH/cxx-dependent-sized-ext-vector.cpp
new file mode 100644
index 000000000000..29c06f7cc797
--- /dev/null
+++ b/test/PCH/cxx-dependent-sized-ext-vector.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++11 -emit-pch %s -o %t
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+template<typename T, int N>
+using vec = T __attribute__((ext_vector_type(N)));
+
+#else
+
+void test() {
+ vec<float, 2> a; // expected-error@-5 {{zero vector size}}
+ vec<float, 0> b; // expected-note {{in instantiation of template type alias 'vec' requested here}}
+}
+
+#endif
diff --git a/test/PCH/cxx-traits.cpp b/test/PCH/cxx-traits.cpp
index b0f1d9d2c3de..01b9e9302d79 100644
--- a/test/PCH/cxx-traits.cpp
+++ b/test/PCH/cxx-traits.cpp
@@ -16,6 +16,7 @@ bool copy_construct_int = n::is_trivially_constructible<int, const int&>::value;
// The built-ins should still work too:
bool _is_abstract_result = __is_abstract(int);
+bool _is_aggregate_result = __is_aggregate(int);
bool _is_arithmetic_result = __is_arithmetic(int);
bool _is_array_result = __is_array(int);
bool _is_assignable_result = __is_assignable(int, int);
diff --git a/test/PCH/cxx-traits.h b/test/PCH/cxx-traits.h
index 1d7d40450fe2..0a4bd09c363e 100644
--- a/test/PCH/cxx-traits.h
+++ b/test/PCH/cxx-traits.h
@@ -18,6 +18,7 @@ struct is_trivially_constructible {
};
struct __is_abstract {}; // expected-warning {{made available}}
+struct __is_aggregate {}; // expected-warning {{made available}}
struct __is_arithmetic {}; // expected-warning {{made available}}
struct __is_array {}; // expected-warning {{made available}}
struct __is_assignable {}; // expected-warning {{made available}}
diff --git a/test/PCH/emit-dependencies.c b/test/PCH/emit-dependencies.c
new file mode 100644
index 000000000000..c4bccf8bb1a6
--- /dev/null
+++ b/test/PCH/emit-dependencies.c
@@ -0,0 +1,9 @@
+// RUN: rm -f %t.pch
+// RUN: %clang_cc1 -emit-pch -o %t.pch %S/Inputs/chain-decls1.h
+// RUN: %clang_cc1 -include-pch %t.pch -fsyntax-only -MT %s.o -dependency-file - %s | FileCheck %s
+// CHECK: chain-decls1.h
+
+int main() {
+ f();
+ return 0;
+}
diff --git a/test/PCH/macro-undef.cpp b/test/PCH/macro-undef.cpp
index c0ce2de23fe3..bfe87d12b208 100644
--- a/test/PCH/macro-undef.cpp
+++ b/test/PCH/macro-undef.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fsyntax-only -include-pch %t %s -Wuninitialized -verify
-// RUN: %clang_cc1 -fsyntax-only -include-pch %t %s -Wuninitialized -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++98 -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -include-pch %t %s -Wuninitialized -verify
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -include-pch %t %s -Wuninitialized -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/ocl_types.h b/test/PCH/ocl_types.h
index bdc4bb11c1b2..96391289f7f3 100644
--- a/test/PCH/ocl_types.h
+++ b/test/PCH/ocl_types.h
@@ -32,9 +32,6 @@ typedef clk_event_t clkevt_t;
// queue_t
typedef queue_t q_t;
-// ndrange_t
-typedef ndrange_t range_t;
-
// reserve_id_t
typedef reserve_id_t reserveid_t;
diff --git a/test/PCH/pragma-pack.c b/test/PCH/pragma-pack.c
new file mode 100644
index 000000000000..47a557002351
--- /dev/null
+++ b/test/PCH/pragma-pack.c
@@ -0,0 +1,90 @@
+// Test this without pch.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DSET
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DRESET
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH_POP
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH_POP_LABEL
+
+// Test with pch.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DSET -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DSET -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DRESET -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DRESET -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP_LABEL -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP_LABEL -verify -include-pch %t
+
+#ifndef HEADER
+#define HEADER
+
+#ifdef SET
+#pragma pack(1)
+#endif
+
+#ifdef RESET
+#pragma pack(2)
+#pragma pack ()
+#endif
+
+#ifdef PUSH
+#pragma pack(1)
+#pragma pack (push, 2)
+#endif
+
+#ifdef PUSH_POP
+#pragma pack (push, 4)
+#pragma pack (push, 2)
+#pragma pack (pop)
+#endif
+
+#ifdef PUSH_POP_LABEL
+#pragma pack (push, a, 4)
+#pragma pack (push, b, 1)
+#pragma pack (push, c, 2)
+#pragma pack (pop, b)
+#endif
+
+#else
+
+#ifdef SET
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 1}}
+#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}}
+#endif
+
+#ifdef RESET
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}}
+#pragma ()
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}}
+#endif
+
+#ifdef PUSH
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 2}}
+#pragma pack(pop)
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 1}}
+#pragma pack ()
+#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 8}}
+#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}}
+#endif
+
+#ifdef PUSH_POP
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 4}}
+#pragma pack(pop)
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}}
+#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}}
+#endif
+
+#ifdef PUSH_POP_LABEL
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 4}}
+#pragma pack(pop, c)
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 4}}
+#pragma pack(pop, a)
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}}
+#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}}
+#pragma pack(pop, b) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}}
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}}
+#endif
+
+#endif
diff --git a/test/Parser/altivec-csk-bool.c b/test/Parser/altivec-csk-bool.c
index c1c253958c66..dc7fa1da3952 100644
--- a/test/Parser/altivec-csk-bool.c
+++ b/test/Parser/altivec-csk-bool.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -faltivec -fsyntax-only %s
-// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -faltivec -fsyntax-only %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -target-feature +altivec -fsyntax-only %s
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -target-feature +altivec -fsyntax-only %s
// PR16456: Verify that bool, true, false are treated as context-sensitive
// keywords (and therefore available for use as identifiers) when in
diff --git a/test/Parser/altivec.c b/test/Parser/altivec.c
index 4d3a7730c35d..769b4dec98fc 100644
--- a/test/Parser/altivec.c
+++ b/test/Parser/altivec.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple=powerpc-apple-darwin8 -faltivec -fsyntax-only -verify %s
-// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -faltivec -fsyntax-only -verify %s
-// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -faltivec -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple=powerpc-apple-darwin8 -target-feature +altivec -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -target-feature +altivec -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -target-feature +altivec -fsyntax-only -verify %s
__vector char vv_c;
__vector signed char vv_sc;
diff --git a/test/Parser/attr-external-source-symbol-cxx11.cpp b/test/Parser/attr-external-source-symbol-cxx11.cpp
new file mode 100644
index 000000000000..3457c6a8f430
--- /dev/null
+++ b/test/Parser/attr-external-source-symbol-cxx11.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
+
+[[clang::external_source_symbol(language="Swift", defined_in="module")]]
+void function() { }
diff --git a/test/Parser/attr-external-source-symbol.m b/test/Parser/attr-external-source-symbol.m
new file mode 100644
index 000000000000..772fde0d48c9
--- /dev/null
+++ b/test/Parser/attr-external-source-symbol.m
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void function() __attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration)));
+
+__attribute__((external_source_symbol(language="Swift", defined_in="module")))
+@interface I
+
+- (void)method __attribute__((external_source_symbol(defined_in= "module")));
+
+@end
+
+enum E {
+ CaseA __attribute__((external_source_symbol(generated_declaration))),
+ CaseB __attribute__((external_source_symbol(generated_declaration, language="Swift")))
+} __attribute__((external_source_symbol(language = "Swift")));
+
+void f2()
+__attribute__((external_source_symbol())); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}}
+void f3()
+__attribute__((external_source_symbol(invalid))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}}
+void f4()
+__attribute__((external_source_symbol(language))); // expected-error {{expected '=' after language}}
+void f5()
+__attribute__((external_source_symbol(language=))); // expected-error {{expected string literal for language name in 'external_source_symbol' attribute}}
+void f6()
+__attribute__((external_source_symbol(defined_in=20))); // expected-error {{expected string literal for source container name in 'external_source_symbol' attribute}}
+
+void f7()
+__attribute__((external_source_symbol(generated_declaration, generated_declaration))); // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}}
+void f8()
+__attribute__((external_source_symbol(language="Swift", language="Swift"))); // expected-error {{duplicate 'language' clause in an 'external_source_symbol' attribute}}
+void f9()
+__attribute__((external_source_symbol(defined_in="module", language="Swift", defined_in="foo"))); // expected-error {{duplicate 'defined_in' clause in an 'external_source_symbol' attribute}}
+
+void f10()
+__attribute__((external_source_symbol(generated_declaration, language="Swift", defined_in="foo", generated_declaration, generated_declaration, language="Swift"))); // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}}
+
+void f11()
+__attribute__((external_source_symbol(language="Objective-C++", defined_in="Some file with spaces")));
+
+void f12()
+__attribute__((external_source_symbol(language="C Sharp", defined_in="file:////Hello world with spaces. cs")));
+
+void f13()
+__attribute__((external_source_symbol(language=Swift))); // expected-error {{expected string literal for language name in 'external_source_symbol' attribute}}
+
+void f14()
+__attribute__((external_source_symbol(=))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}}
+
+void f15()
+__attribute__((external_source_symbol(="Swift"))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}}
+
+void f16()
+__attribute__((external_source_symbol("Swift", "module", generated_declaration))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}}
+
+void f17()
+__attribute__((external_source_symbol(language="Swift", "generated_declaration"))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}}
+
+void f18()
+__attribute__((external_source_symbol(language= =))); // expected-error {{expected string literal for language name in 'external_source_symbol' attribute}}
+
+void f19()
+__attribute__((external_source_symbol(defined_in="module" language="swift"))); // expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+void f20()
+__attribute__((external_source_symbol(defined_in="module" language="swift" generated_declaration))); // expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+void f21()
+__attribute__((external_source_symbol(defined_in= language="swift"))); // expected-error {{expected string literal for source container name in 'external_source_symbol' attribute}}
+
+void f22()
+__attribute__((external_source_symbol)); // expected-error {{'external_source_symbol' attribute takes at least 1 argument}}
+
+void f23()
+__attribute__((external_source_symbol(defined_in=, language="swift" generated_declaration))); // expected-error {{expected string literal for source container name in 'external_source_symbol' attribute}} expected-error{{expected ')'}} expected-note{{to match this '('}}
+
+void f24()
+__attribute__((external_source_symbol(language = generated_declaration))); // expected-error {{expected string literal for language name in 'external_source_symbol' attribute}}
+
+void f25()
+__attribute__((external_source_symbol(defined_in=123, defined_in="module"))); // expected-error {{expected string literal for source container name in 'external_source_symbol'}} expected-error {{duplicate 'defined_in' clause in an 'external_source_symbol' attribute}}
+
+void f26()
+__attribute__((external_source_symbol(language=Swift, language="Swift", error))); // expected-error {{expected string literal for language name in 'external_source_symbol'}} expected-error {{duplicate 'language' clause in an 'external_source_symbol' attribute}} expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}}
diff --git a/test/Parser/backtrack-off-by-one.cpp b/test/Parser/backtrack-off-by-one.cpp
index efb95a5a225d..52e1c4147839 100644
--- a/test/Parser/backtrack-off-by-one.cpp
+++ b/test/Parser/backtrack-off-by-one.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -verify %s
// RUN: %clang_cc1 -verify %s -std=c++98
// RUN: %clang_cc1 -verify %s -std=c++11
+// RUN: %clang_cc1 -verify %s -std=c++1z
// PR25946
// We had an off-by-one error in an assertion when annotating A<int> below. Our
@@ -13,9 +14,13 @@ template <typename T> class A {};
// expected-error@+1 {{expected '{' after base class list}}
template <typename T> class B : T // not ',' or '{'
#if __cplusplus < 201103L
-// expected-error@+4 {{expected ';' after top level declarator}}
+// expected-error@+8 {{expected ';' after top level declarator}}
+#endif
+#if __cplusplus <= 201402L
+// expected-error@+5 {{C++ requires a type specifier for all declarations}}
+#else
+// expected-error@+3 {{expected unqualified-id}}
#endif
-// expected-error@+2 {{C++ requires a type specifier for all declarations}}
// expected-error@+1 {{expected ';' after class}}
A<int> {
};
diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp
index 5b0da6c5e6fd..6395452010d4 100644
--- a/test/Parser/cxx-altivec.cpp
+++ b/test/Parser/cxx-altivec.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple=powerpc-apple-darwin8 -faltivec -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -faltivec -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -faltivec -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple=powerpc-apple-darwin8 -target-feature +altivec -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -target-feature +altivec -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -target-feature +altivec -fsyntax-only -verify -std=c++11 %s
#include <altivec.h>
__vector char vv_c;
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index efa42ad30d04..9ad422e7ab71 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -238,3 +238,13 @@ struct t2 : base<int,
// expected-error@-1 {{expected '{' after base class list}}
}
+
+namespace class_scope_instantiation {
+ struct A {
+ template<typename T> void f(T);
+ template void f<int>(int); // expected-error {{expected '<' after 'template'}}
+ template void f(float); // expected-error {{expected '<' after 'template'}}
+ extern template // expected-error {{expected member name or ';'}}
+ void f(double);
+ };
+}
diff --git a/test/Parser/cxx0x-ambig.cpp b/test/Parser/cxx0x-ambig.cpp
index a47585f8b643..4a1b4ad777a6 100644
--- a/test/Parser/cxx0x-ambig.cpp
+++ b/test/Parser/cxx0x-ambig.cpp
@@ -109,7 +109,7 @@ namespace trailing_return {
namespace ellipsis {
template<typename...T>
struct S {
- void e(S::S());
+ void e(S::S()); // expected-error {{is a constructor name}}
void f(S(...args[sizeof(T)])); // expected-note {{here}} expected-note {{here}}
void f(S(...args)[sizeof(T)]); // expected-error {{redeclared}}
void f(S ...args[sizeof(T)]); // expected-error {{redeclared}}
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 906d72b087cb..647762f165cb 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -99,11 +99,13 @@ void fn_with_structs() {
}
[[]];
struct ctordtor {
- [[]] ctordtor();
- [[]] ~ctordtor();
+ [[]] ctordtor [[]] () [[]];
+ ctordtor (C) [[]];
+ [[]] ~ctordtor [[]] () [[]];
};
-[[]] ctordtor::ctordtor() {}
-[[]] ctordtor::~ctordtor() {}
+[[]] ctordtor::ctordtor [[]] () [[]] {}
+[[]] ctordtor::ctordtor (C) [[]] try {} catch (...) {}
+[[]] ctordtor::~ctordtor [[]] () [[]] {}
extern "C++" [[]] int extern_attr;
template <typename T> [[]] void template_attr ();
[[]] [[]] int [[]] [[]] multi_attr [[]] [[]];
diff --git a/test/Parser/cxx11-stmt-attributes.cpp b/test/Parser/cxx11-stmt-attributes.cpp
index 9374b58b1f24..75fb37ea9fb4 100644
--- a/test/Parser/cxx11-stmt-attributes.cpp
+++ b/test/Parser/cxx11-stmt-attributes.cpp
@@ -80,5 +80,6 @@ void foo(int i) {
{
[[ ]] // expected-error {{an attribute list cannot appear here}}
#pragma STDC FP_CONTRACT ON // expected-error {{can only appear at file scope or at the start of a compound statement}}
+#pragma clang fp contract(fast) // expected-error {{can only appear at file scope or at the start of a compound statement}}
}
}
diff --git a/test/Parser/cxx1z-class-template-argument-deduction.cpp b/test/Parser/cxx1z-class-template-argument-deduction.cpp
new file mode 100644
index 000000000000..dac17dfbf480
--- /dev/null
+++ b/test/Parser/cxx1z-class-template-argument-deduction.cpp
@@ -0,0 +1,194 @@
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
+
+template <typename T> struct A { // expected-note 35{{declared here}}
+ constexpr A() {}
+ constexpr A(int) {}
+ constexpr operator int() { return 0; }
+};
+A() -> A<int>;
+A(int) -> A<int>;
+
+// Make sure we still correctly parse cases where a template can appear without arguments.
+namespace template_template_arg {
+ template<template<typename> typename> struct X {};
+ template<typename> struct Y {};
+
+ X<A> xa;
+ Y<A> ya; // expected-error {{requires template arguments}}
+ X<::A> xcca;
+ Y<::A> ycca; // expected-error {{requires template arguments}}
+
+ template<template<typename> typename = A> struct XD {};
+ template<typename = A> struct YD {}; // expected-error {{requires template arguments}}
+ template<template<typename> typename = ::A> struct XCCD {};
+ template<typename = ::A> struct YCCD {}; // expected-error {{requires template arguments}}
+
+ // FIXME: replacing the invalid type with 'int' here is horrible
+ template <A a = A<int>()> class C { }; // expected-error {{requires template arguments}}
+ template<typename T = A> struct G { }; // expected-error {{requires template arguments}}
+}
+
+namespace injected_class_name {
+ template<typename T> struct A {
+ A(T);
+ void f(int) { // expected-note {{previous}}
+ A a = 1;
+ injected_class_name::A b = 1; // expected-note {{in instantiation of template class 'injected_class_name::A<int>'}}
+ }
+ void f(T); // expected-error {{multiple overloads of 'f' instantiate to the same signature 'void (int)}}
+ };
+ A<short> ai = 1;
+ A<double>::A b(1); // expected-error {{constructor name}}
+}
+
+struct member {
+ A a; // expected-error {{requires template arguments}}
+ A *b; // expected-error {{requires template arguments}}
+ const A c; // expected-error {{requires template arguments}}
+
+ void f() throw (A); // expected-error {{requires template arguments}}
+
+ friend A; // expected-error {{requires template arguments; argument deduction not allowed in friend declaration}}
+
+ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}}
+
+ static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}}
+ static constexpr A y = 0;
+};
+
+namespace in_typedef {
+ typedef A *AutoPtr; // expected-error {{requires template arguments; argument deduction not allowed in typedef}}
+ typedef A (*PFun)(int a); // expected-error{{requires template arguments; argument deduction not allowed in typedef}}
+ typedef A Fun(int a) -> decltype(a + a); // expected-error{{requires template arguments; argument deduction not allowed in function return type}}
+}
+
+namespace stmt {
+ void g(A a) { // expected-error{{requires template arguments; argument deduction not allowed in function prototype}}
+ try { }
+ catch (A &a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}}
+ catch (const A a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}}
+ try { } catch (A a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}}
+
+ // FIXME: The standard only permits class template argument deduction in a
+ // simple-declaration or cast. We also permit it in conditions,
+ // for-range-declarations, member-declarations for static data members, and
+ // new-expressions, because not doing so would be bizarre.
+ A local = 0;
+ static A local_static = 0;
+ static thread_local A thread_local_static = 0;
+ if (A a = 0) {}
+ if (A a = 0; a) {}
+ switch (A a = 0) {} // expected-warning {{no case matching constant switch condition '0'}}
+ switch (A a = 0; a) {} // expected-warning {{no case matching constant switch condition '0'}}
+ for (A a = 0; a; /**/) {}
+ for (/**/; A a = 0; /**/) {}
+ while (A a = 0) {}
+ int arr[3];
+ for (A a : arr) {}
+ }
+
+ namespace std {
+ class type_info;
+ }
+}
+
+namespace expr {
+ template<typename T> struct U {};
+ void j() {
+ (void)typeid(A); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)sizeof(A); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)__alignof(A); // expected-error{{requires template arguments; argument deduction not allowed here}}
+
+ U<A> v; // expected-error {{requires template arguments}}
+
+ int n;
+ (void)dynamic_cast<A&>(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)static_cast<A*>(&n); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)reinterpret_cast<A*>(&n); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)const_cast<A>(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)*(A*)(&n); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)(A)(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)(A){n}; // expected-error{{requires template arguments; argument deduction not allowed here}}
+
+ (void)A(n);
+ (void)A{n};
+ (void)new A(n);
+ (void)new A{n};
+ // FIXME: We should diagnose the lack of an initializer here.
+ (void)new A;
+ }
+}
+
+namespace decl {
+ enum E : A {}; // expected-error{{requires template arguments; argument deduction not allowed here}}
+ struct F : A {}; // expected-error{{expected class name}}
+
+ using B = A; // expected-error{{requires template arguments}}
+
+ auto k() -> A; // expected-error{{requires template arguments}}
+
+ A a; // expected-error {{declaration of variable 'a' with deduced type 'A' requires an initializer}}
+ A b = 0;
+ const A c = 0;
+ A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
+ A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
+ A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
+ A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
+ A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
+ A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
+ A [x, y] = 0; // expected-error {{cannot be declared with type 'A'}} expected-error {{type 'A<int>' decomposes into 0 elements, but 2 names were provided}}
+}
+
+namespace typename_specifier {
+ struct F {};
+
+ void e() {
+ (void) typename ::A(0);
+ (void) typename ::A{0};
+ new typename ::A(0);
+ new typename ::A{0};
+ typename ::A a = 0;
+ const typename ::A b = 0;
+ if (typename ::A a = 0) {}
+ for (typename ::A a = 0; typename ::A b = 0; /**/) {}
+
+ (void)(typename ::A)(0); // expected-error{{requires template arguments; argument deduction not allowed here}}
+ (void)(typename ::A){0}; // expected-error{{requires template arguments; argument deduction not allowed here}}
+ }
+ typename ::A a = 0;
+ const typename ::A b = 0;
+ typename ::A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
+ typename ::A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
+ typename ::A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
+ typename ::A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
+ typename ::A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
+ typename ::A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
+ typename ::A [x, y] = 0; // expected-error {{cannot be declared with type 'typename ::A'}} expected-error {{type 'typename ::A<int>' (aka 'A<int>') decomposes into 0}}
+
+ struct X { template<typename T> struct A { A(T); }; }; // expected-note 8{{declared here}}
+
+ template<typename T> void f() {
+ (void) typename T::A(0);
+ (void) typename T::A{0};
+ new typename T::A(0);
+ new typename T::A{0};
+ typename T::A a = 0;
+ const typename T::A b = 0;
+ if (typename T::A a = 0) {} // expected-error {{value of type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') is not contextually convertible to 'bool'}}
+ for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error {{value of type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') is not contextually convertible to 'bool'}}
+
+ {(void)(typename T::A)(0);} // expected-error{{refers to class template member}}
+ {(void)(typename T::A){0};} // expected-error{{refers to class template member}}
+ {typename T::A (parens) = 0;} // expected-error {{refers to class template member in 'typename_specifier::X'; argument deduction not allowed here}}
+ {typename T::A *p = 0;} // expected-error {{refers to class template member}}
+ {typename T::A &r = *p;} // expected-error {{refers to class template member}}
+ {typename T::A arr[3] = 0;} // expected-error {{refers to class template member}}
+ {typename T::A F::*pm = 0;} // expected-error {{refers to class template member}}
+ {typename T::A (*fp)() = 0;} // expected-error {{refers to class template member}}
+ {typename T::A [x, y] = 0;} // expected-error {{cannot be declared with type 'typename T::A'}} expected-error {{type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') decomposes into 0}}
+ }
+ template void f<X>(); // expected-note {{instantiation of}}
+
+ template<typename T> void g(typename T::A = 0); // expected-note {{refers to class template member}}
+ void h() { g<X>(); } // expected-error {{no matching function}}
+}
diff --git a/test/Parser/declspec-recovery.c b/test/Parser/declspec-recovery.c
new file mode 100644
index 000000000000..b256861b9f39
--- /dev/null
+++ b/test/Parser/declspec-recovery.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -verify %s
+
+__declspec(naked) void f(void) {} // expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for __declspec attributes}}
+
+struct S {
+ __declspec(property(get=Getter, put=Setter)) int X; // expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for __declspec attributes}}
+ int Y;
+};
diff --git a/test/Parser/declspec-supported.c b/test/Parser/declspec-supported.c
new file mode 100644
index 000000000000..f9004893a4a2
--- /dev/null
+++ b/test/Parser/declspec-supported.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fms-extensions -verify %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fdeclspec -verify %s
+// expected-no-diagnostics
+
+__declspec(naked) void f(void) {}
+
+struct S {
+ __declspec(property(get=Getter, put=Setter)) int X;
+ int Y;
+};
diff --git a/test/Parser/eof.cpp b/test/Parser/eof.cpp
index 3c966c50e1db..4a06587edea3 100644
--- a/test/Parser/eof.cpp
+++ b/test/Parser/eof.cpp
@@ -1,6 +1,6 @@
// RUN: not %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
-// CHECK: error: expected member name or ';' after declaration specifiers
+// CHECK: error: expected '<' after 'template'
// CHECK: error: expected '}'
// CHECK: note: to match this '{'
// CHECK: error: expected ';' after class
diff --git a/test/Parser/objc-available.m b/test/Parser/objc-available.m
index d18ac1f13445..a170721240ce 100644
--- a/test/Parser/objc-available.m
+++ b/test/Parser/objc-available.m
@@ -20,3 +20,8 @@ void f() {
(void)@available(macos); // expected-error{{expected a version}}
(void)@available; // expected-error{{expected '('}}
}
+
+#if __has_builtin(__builtin_available)
+#error expected
+// expected-error@-1 {{expected}}
+#endif
diff --git a/test/Parser/objc-cxx-keyword-identifiers.mm b/test/Parser/objc-cxx-keyword-identifiers.mm
new file mode 100644
index 000000000000..6791f0d3732a
--- /dev/null
+++ b/test/Parser/objc-cxx-keyword-identifiers.mm
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-objc-root-class -Wno-incomplete-implementation -triple x86_64-apple-macosx10.10.0 -verify %s
+
+// rdar://20626062
+
+struct S {
+ int throw; // expected-error {{expected member name or ';' after declaration specifiers; 'throw' is a keyword in Objective-C++}}
+};
+
+@interface class // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+@end
+
+@interface Bar: class // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+@end
+
+@protocol P // ok
+@end
+
+@protocol new // expected-error {{expected identifier; 'new' is a keyword in Objective-C++}}
+@end
+
+@protocol P2, delete; // expected-error {{expected identifier; 'delete' is a keyword in Objective-C++}}
+
+@class Foo, try; // expected-error {{expected identifier; 'try' is a keyword in Objective-C++}}
+
+@interface Foo
+
+@property (readwrite, nonatomic) int a, b, throw; // expected-error {{expected member name or ';' after declaration specifiers; 'throw' is a keyword in Objective-C++}}
+
+-foo:(int)class; // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
++foo:(int)constexpr; // expected-error {{expected identifier; 'constexpr' is a keyword in Objective-C++}}
+
+@end
+
+@interface Foo () <P, new> // expected-error {{expected identifier; 'new' is a keyword in Objective-C++}}
+@end
+
+@implementation Foo
+
+@synthesize a = _a; // ok
+@synthesize b = virtual; // expected-error {{expected identifier; 'virtual' is a keyword in Objective-C++}}
+
+@dynamic throw; // expected-error {{expected identifier; 'throw' is a keyword in Objective-C++}}
+
+-foo:(int)class { // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+}
+
+@end
+
+@implementation class // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+@end
+
+@implementation Bar: class // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+@end
+
+@compatibility_alias C Foo; // ok
+@compatibility_alias const_cast Bar; // expected-error {{expected identifier; 'const_cast' is a keyword in Objective-C++}}
+@compatibility_alias C2 class; // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+
+void func() {
+ (void)@protocol(P); // ok
+ (void)@protocol(delete); // expected-error {{expected identifier; 'delete' is a keyword in Objective-C++}}
+}
diff --git a/test/Parser/opencl-atomics-cl20.cl b/test/Parser/opencl-atomics-cl20.cl
index 65fb9d9b42a8..ad67db0bab8a 100644
--- a/test/Parser/opencl-atomics-cl20.cl
+++ b/test/Parser/opencl-atomics-cl20.cl
@@ -67,7 +67,7 @@ void atomic_ops_test() {
foo(&i);
// OpenCL v2.0 s6.13.11.8, arithemtic operations are not permitted on atomic types.
i++; // expected-error {{invalid argument type 'atomic_int' (aka '_Atomic(int)') to unary expression}}
- i = 1; // expected-error {{atomic variable can only be assigned to a compile time constant in the declaration statement in the program scope}}
+ i = 1; // expected-error {{atomic variable can be assigned to a variable only in global address space}}
i += 1; // expected-error {{invalid operands to binary expression ('atomic_int' (aka '_Atomic(int)') and 'int')}}
i = i + i; // expected-error {{invalid operands to binary expression ('atomic_int' (aka '_Atomic(int)') and 'atomic_int')}}
}
diff --git a/test/Parser/pragma-fp.cpp b/test/Parser/pragma-fp.cpp
new file mode 100644
index 000000000000..00547bfb546a
--- /dev/null
+++ b/test/Parser/pragma-fp.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+void test_0(int *List, int Length) {
+/* expected-error@+1 {{missing option; expected contract}} */
+#pragma clang fp
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+void test_1(int *List, int Length) {
+/* expected-error@+1 {{invalid option 'blah'; expected contract}} */
+#pragma clang fp blah
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+void test_3(int *List, int Length) {
+/* expected-error@+1 {{expected '('}} */
+#pragma clang fp contract on
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+void test_4(int *List, int Length) {
+/* expected-error@+1 {{unexpected argument 'while' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */
+#pragma clang fp contract(while)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+void test_5(int *List, int Length) {
+/* expected-error@+1 {{unexpected argument 'maybe' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */
+#pragma clang fp contract(maybe)
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+void test_6(int *List, int Length) {
+/* expected-error@+1 {{expected ')'}} */
+#pragma clang fp contract(fast
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+void test_7(int *List, int Length) {
+/* expected-warning@+1 {{extra tokens at end of '#pragma clang fp' - ignored}} */
+#pragma clang fp contract(fast) *
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+ }
+}
+
+void test_8(int *List, int Length) {
+ for (int i = 0; i < Length; i++) {
+ List[i] = i;
+/* expected-error@+1 {{'#pragma clang fp' can only appear at file scope or at the start of a compound statement}} */
+#pragma clang fp contract(fast)
+ }
+}
diff --git a/test/Parser/vector-cast-define.cl b/test/Parser/vector-cast-define.cl
new file mode 100644
index 000000000000..ec4eba7a7848
--- /dev/null
+++ b/test/Parser/vector-cast-define.cl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
+
+typedef int int3 __attribute__((ext_vector_type(3)));
+
+void test()
+{
+ int index = (int3)(1, 2, 3).x * (int3)(3, 2, 1).y;
+}
+
diff --git a/test/Parser/vsx.c b/test/Parser/vsx.c
index ead09814c8c1..32bc934a7eb6 100644
--- a/test/Parser/vsx.c
+++ b/test/Parser/vsx.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -faltivec -target-feature +vsx -fsyntax-only -verify %s
-// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -faltivec -target-feature +vsx -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -target-feature +altivec -target-feature +vsx -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -target-feature +altivec -target-feature +vsx -fsyntax-only -verify %s
// Legitimate for VSX.
__vector double vv_d1;
diff --git a/test/Preprocessor/aarch64-target-features.c b/test/Preprocessor/aarch64-target-features.c
index aef788dd083e..c9c7f2dc4a4e 100644
--- a/test/Preprocessor/aarch64-target-features.c
+++ b/test/Preprocessor/aarch64-target-features.c
@@ -97,7 +97,7 @@
// RUN: %clang -target aarch64 -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-M1 %s
// RUN: %clang -target aarch64 -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-M1 %s
// RUN: %clang -target aarch64 -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-KRYO %s
-// RUN: %clang -target aarch64 -mcpu=vulcan -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-VULCAN %s
+// RUN: %clang -target aarch64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-THUNDERX2T99 %s
// CHECK-MCPU-CYCLONE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crypto" "-target-feature" "+zcm" "-target-feature" "+zcz"
// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
@@ -106,7 +106,7 @@
// CHECK-MCPU-CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// CHECK-MCPU-M1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// CHECK-MCPU-KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
-// CHECK-MCPU-VULCAN: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
+// CHECK-MCPU-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
// RUN: %clang -target x86_64-apple-macosx -arch arm64 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64 %s
// CHECK-ARCH-ARM64: "-target-cpu" "cyclone" "-target-feature" "+neon" "-target-feature" "+crypto" "-target-feature" "+zcm" "-target-feature" "+zcz"
diff --git a/test/Preprocessor/arm-acle-6.4.c b/test/Preprocessor/arm-acle-6.4.c
index 11be2c172f3b..3102bd48cabc 100644
--- a/test/Preprocessor/arm-acle-6.4.c
+++ b/test/Preprocessor/arm-acle-6.4.c
@@ -120,6 +120,21 @@
// CHECK-V7A-NO-IDIV-NOT: __ARM_FEATURE_IDIV
+// RUN: %clang -target arm-none-linux-eabi -march=armv7ve -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-V7VE
+
+// CHECK-V7VE: __ARM_ARCH 7
+// CHECK-V7VE: __ARM_ARCH_ISA_ARM 1
+// CHECK-V7VE: __ARM_ARCH_ISA_THUMB 2
+// CHECK-V7VE: __ARM_ARCH_PROFILE 'A'
+// CHECK-V7VE: __ARM_FEATURE_CLZ 1
+// CHECK-V7VE: __ARM_FEATURE_DSP 1
+// CHECK-V7VE: __ARM_FEATURE_IDIV 1
+// CHECK-V7VE: __ARM_FEATURE_LDREX 0xF
+// CHECK-V7VE: __ARM_FEATURE_QBIT 1
+// CHECK-V7VE: __ARM_FEATURE_SAT 1
+// CHECK-V7VE: __ARM_FEATURE_SIMD32 1
+// CHECK-V7VE: __ARM_FEATURE_UNALIGNED 1
+
// RUN: %clang -target arm-none-linux-eabi -march=armv7-r -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-V7R
// CHECK-V7R: __ARM_ARCH 7
diff --git a/test/Preprocessor/arm-acle-6.5.c b/test/Preprocessor/arm-acle-6.5.c
index cc158c82cd8a..7ad91bd7fc85 100644
--- a/test/Preprocessor/arm-acle-6.5.c
+++ b/test/Preprocessor/arm-acle-6.5.c
@@ -24,6 +24,7 @@
// RUN: %clang -target arm-eabi -mfpu=neon -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
// RUN: %clang -target armv6-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
// RUN: %clang -target armv7a-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
+// RUN: %clang -target armv7ve-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-SP-DP
// CHECK-SP-DP: __ARM_FP 0xC
@@ -51,6 +52,8 @@
// RUN: %clang -target armv7a-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-NO-FMA
// RUN: %clang -target armv7a-eabi -mfpu=vfpv4 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-FMA
+// RUN: %clang -target armv7ve-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-NO-FMA
+// RUN: %clang -target armv7ve-eabi -mfpu=vfpv4 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-FMA
// RUN: %clang -target armv7r-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-NO-FMA
// RUN: %clang -target armv7r-eabi -mfpu=vfpv4 -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-FMA
// RUN: %clang -target armv7em-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-FMA
diff --git a/test/Preprocessor/arm-target-features.c b/test/Preprocessor/arm-target-features.c
index f45c5ba07f0f..81dab475fc9d 100644
--- a/test/Preprocessor/arm-target-features.c
+++ b/test/Preprocessor/arm-target-features.c
@@ -27,6 +27,13 @@
// CHECK-V7-NOT: __ARM_FEATURE_DIRECTED_ROUNDING
// CHECK-V7: #define __ARM_FP 0xC
+// RUN: %clang -target armv7ve-none-linux-gnu -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V7VE %s
+// CHECK-V7VE: #define __ARMEL__ 1
+// CHECK-V7VE: #define __ARM_ARCH 7
+// CHECK-V7VE: #define __ARM_ARCH_7VE__ 1
+// CHECK-V7VE: #define __ARM_ARCH_EXT_IDIV__ 1
+// CHECK-V7VE: #define __ARM_FP 0xC
+
// RUN: %clang -target x86_64-apple-macosx10.10 -arch armv7s -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V7S %s
// CHECK-V7S: #define __ARMEL__ 1
// CHECK-V7S: #define __ARM_ARCH 7
@@ -391,6 +398,31 @@
// M7-THUMB:#define __ARM_FP 0xE
// M7-THUMB:#define __ARM_FPV5__ 1
+// Test whether predefines are as expected when targeting v8m cores
+// RUN: %clang -target arm -mcpu=cortex-m23 -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=M23 %s
+// M23: #define __ARM_ARCH 8
+// M23: #define __ARM_ARCH_8M_BASE__ 1
+// M23: #define __ARM_ARCH_EXT_IDIV__ 1
+// M23-NOT: __ARM_ARCH_ISA_ARM
+// M23: #define __ARM_ARCH_ISA_THUMB 1
+// M23: #define __ARM_ARCH_PROFILE 'M'
+// M23-NOT: __ARM_FEATURE_CRC32
+// M23-NOT: __ARM_FEATURE_DSP
+// M23-NOT: __ARM_FP 0x{{.*}}
+// M23-NOT: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+
+// RUN: %clang -target arm -mcpu=cortex-m33 -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=M33 %s
+// M33: #define __ARM_ARCH 8
+// M33: #define __ARM_ARCH_8M_MAIN__ 1
+// M33: #define __ARM_ARCH_EXT_IDIV__ 1
+// M33-NOT: __ARM_ARCH_ISA_ARM
+// M33: #define __ARM_ARCH_ISA_THUMB 2
+// M33: #define __ARM_ARCH_PROFILE 'M'
+// M33-NOT: __ARM_FEATURE_CRC32
+// M33: #define __ARM_FEATURE_DSP 1
+// M33: #define __ARM_FP 0x6
+// M33: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
+
// Test whether predefines are as expected when targeting krait.
// RUN: %clang -target armv7 -mcpu=krait -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=KRAIT %s
// RUN: %clang -target armv7 -mthumb -mcpu=krait -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=KRAIT %s
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 8b8901931e7a..d48d476d7009 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -15,7 +15,7 @@
// CXX1Z:#define __GXX_EXPERIMENTAL_CXX0X__ 1
// CXX1Z:#define __GXX_RTTI 1
// CXX1Z:#define __GXX_WEAK__ 1
-// CXX1Z:#define __cplusplus 201406L
+// CXX1Z:#define __cplusplus 201703L
// CXX1Z:#define __private_extern__ extern
//
//
@@ -115,7 +115,7 @@
//
// GXX1Z:#define __GNUG__ {{.*}}
// GXX1Z:#define __GXX_WEAK__ 1
-// GXX1Z:#define __cplusplus 201406L
+// GXX1Z:#define __cplusplus 201703L
// GXX1Z:#define __private_extern__ extern
//
//
@@ -831,6 +831,198 @@
// AARCH64-NETBSD:#define __WINT_WIDTH__ 32
// AARCH64-NETBSD:#define __aarch64__ 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-openbsd < /dev/null | FileCheck -match-full-lines -check-prefix AARCH64-OPENBSD %s
+//
+// AARCH64-OPENBSD:#define _LP64 1
+// AARCH64-OPENBSD-NOT:#define __AARCH64EB__ 1
+// AARCH64-OPENBSD:#define __AARCH64EL__ 1
+// AARCH64-OPENBSD-NOT:#define __AARCH_BIG_ENDIAN 1
+// AARCH64-OPENBSD:#define __ARM_64BIT_STATE 1
+// AARCH64-OPENBSD:#define __ARM_ARCH 8
+// AARCH64-OPENBSD:#define __ARM_ARCH_ISA_A64 1
+// AARCH64-OPENBSD-NOT:#define __ARM_BIG_ENDIAN 1
+// AARCH64-OPENBSD:#define __BIGGEST_ALIGNMENT__ 16
+// AARCH64-OPENBSD:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// AARCH64-OPENBSD:#define __CHAR16_TYPE__ unsigned short
+// AARCH64-OPENBSD:#define __CHAR32_TYPE__ unsigned int
+// AARCH64-OPENBSD:#define __CHAR_BIT__ 8
+// AARCH64-OPENBSD:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// AARCH64-OPENBSD:#define __DBL_DIG__ 15
+// AARCH64-OPENBSD:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// AARCH64-OPENBSD:#define __DBL_HAS_DENORM__ 1
+// AARCH64-OPENBSD:#define __DBL_HAS_INFINITY__ 1
+// AARCH64-OPENBSD:#define __DBL_HAS_QUIET_NAN__ 1
+// AARCH64-OPENBSD:#define __DBL_MANT_DIG__ 53
+// AARCH64-OPENBSD:#define __DBL_MAX_10_EXP__ 308
+// AARCH64-OPENBSD:#define __DBL_MAX_EXP__ 1024
+// AARCH64-OPENBSD:#define __DBL_MAX__ 1.7976931348623157e+308
+// AARCH64-OPENBSD:#define __DBL_MIN_10_EXP__ (-307)
+// AARCH64-OPENBSD:#define __DBL_MIN_EXP__ (-1021)
+// AARCH64-OPENBSD:#define __DBL_MIN__ 2.2250738585072014e-308
+// AARCH64-OPENBSD:#define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__
+// AARCH64-OPENBSD:#define __ELF__ 1
+// AARCH64-OPENBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// AARCH64-OPENBSD:#define __FLT_DIG__ 6
+// AARCH64-OPENBSD:#define __FLT_EPSILON__ 1.19209290e-7F
+// AARCH64-OPENBSD:#define __FLT_EVAL_METHOD__ 0
+// AARCH64-OPENBSD:#define __FLT_HAS_DENORM__ 1
+// AARCH64-OPENBSD:#define __FLT_HAS_INFINITY__ 1
+// AARCH64-OPENBSD:#define __FLT_HAS_QUIET_NAN__ 1
+// AARCH64-OPENBSD:#define __FLT_MANT_DIG__ 24
+// AARCH64-OPENBSD:#define __FLT_MAX_10_EXP__ 38
+// AARCH64-OPENBSD:#define __FLT_MAX_EXP__ 128
+// AARCH64-OPENBSD:#define __FLT_MAX__ 3.40282347e+38F
+// AARCH64-OPENBSD:#define __FLT_MIN_10_EXP__ (-37)
+// AARCH64-OPENBSD:#define __FLT_MIN_EXP__ (-125)
+// AARCH64-OPENBSD:#define __FLT_MIN__ 1.17549435e-38F
+// AARCH64-OPENBSD:#define __FLT_RADIX__ 2
+// AARCH64-OPENBSD:#define __INT16_C_SUFFIX__
+// AARCH64-OPENBSD:#define __INT16_FMTd__ "hd"
+// AARCH64-OPENBSD:#define __INT16_FMTi__ "hi"
+// AARCH64-OPENBSD:#define __INT16_MAX__ 32767
+// AARCH64-OPENBSD:#define __INT16_TYPE__ short
+// AARCH64-OPENBSD:#define __INT32_C_SUFFIX__
+// AARCH64-OPENBSD:#define __INT32_FMTd__ "d"
+// AARCH64-OPENBSD:#define __INT32_FMTi__ "i"
+// AARCH64-OPENBSD:#define __INT32_MAX__ 2147483647
+// AARCH64-OPENBSD:#define __INT32_TYPE__ int
+// AARCH64-OPENBSD:#define __INT64_C_SUFFIX__ LL
+// AARCH64-OPENBSD:#define __INT64_FMTd__ "lld"
+// AARCH64-OPENBSD:#define __INT64_FMTi__ "lli"
+// AARCH64-OPENBSD:#define __INT64_MAX__ 9223372036854775807LL
+// AARCH64-OPENBSD:#define __INT64_TYPE__ long long int
+// AARCH64-OPENBSD:#define __INT8_C_SUFFIX__
+// AARCH64-OPENBSD:#define __INT8_FMTd__ "hhd"
+// AARCH64-OPENBSD:#define __INT8_FMTi__ "hhi"
+// AARCH64-OPENBSD:#define __INT8_MAX__ 127
+// AARCH64-OPENBSD:#define __INT8_TYPE__ signed char
+// AARCH64-OPENBSD:#define __INTMAX_C_SUFFIX__ LL
+// AARCH64-OPENBSD:#define __INTMAX_FMTd__ "lld"
+// AARCH64-OPENBSD:#define __INTMAX_FMTi__ "lli"
+// AARCH64-OPENBSD:#define __INTMAX_MAX__ 9223372036854775807LL
+// AARCH64-OPENBSD:#define __INTMAX_TYPE__ long long int
+// AARCH64-OPENBSD:#define __INTMAX_WIDTH__ 64
+// AARCH64-OPENBSD:#define __INTPTR_FMTd__ "ld"
+// AARCH64-OPENBSD:#define __INTPTR_FMTi__ "li"
+// AARCH64-OPENBSD:#define __INTPTR_MAX__ 9223372036854775807L
+// AARCH64-OPENBSD:#define __INTPTR_TYPE__ long int
+// AARCH64-OPENBSD:#define __INTPTR_WIDTH__ 64
+// AARCH64-OPENBSD:#define __INT_FAST16_FMTd__ "hd"
+// AARCH64-OPENBSD:#define __INT_FAST16_FMTi__ "hi"
+// AARCH64-OPENBSD:#define __INT_FAST16_MAX__ 32767
+// AARCH64-OPENBSD:#define __INT_FAST16_TYPE__ short
+// AARCH64-OPENBSD:#define __INT_FAST32_FMTd__ "d"
+// AARCH64-OPENBSD:#define __INT_FAST32_FMTi__ "i"
+// AARCH64-OPENBSD:#define __INT_FAST32_MAX__ 2147483647
+// AARCH64-OPENBSD:#define __INT_FAST32_TYPE__ int
+// AARCH64-OPENBSD:#define __INT_FAST64_FMTd__ "ld"
+// AARCH64-OPENBSD:#define __INT_FAST64_FMTi__ "li"
+// AARCH64-OPENBSD:#define __INT_FAST64_MAX__ 9223372036854775807L
+// AARCH64-OPENBSD:#define __INT_FAST64_TYPE__ long int
+// AARCH64-OPENBSD:#define __INT_FAST8_FMTd__ "hhd"
+// AARCH64-OPENBSD:#define __INT_FAST8_FMTi__ "hhi"
+// AARCH64-OPENBSD:#define __INT_FAST8_MAX__ 127
+// AARCH64-OPENBSD:#define __INT_FAST8_TYPE__ signed char
+// AARCH64-OPENBSD:#define __INT_LEAST16_FMTd__ "hd"
+// AARCH64-OPENBSD:#define __INT_LEAST16_FMTi__ "hi"
+// AARCH64-OPENBSD:#define __INT_LEAST16_MAX__ 32767
+// AARCH64-OPENBSD:#define __INT_LEAST16_TYPE__ short
+// AARCH64-OPENBSD:#define __INT_LEAST32_FMTd__ "d"
+// AARCH64-OPENBSD:#define __INT_LEAST32_FMTi__ "i"
+// AARCH64-OPENBSD:#define __INT_LEAST32_MAX__ 2147483647
+// AARCH64-OPENSD:#define __INT_LEAST32_TYPE__ int
+// AARCH64-OPENBSD:#define __INT_LEAST64_FMTd__ "ld"
+// AARCH64-OPENBSD:#define __INT_LEAST64_FMTi__ "li"
+// AARCH64-OPENBSD:#define __INT_LEAST64_MAX__ 9223372036854775807L
+// AARCH64-OPENBSD:#define __INT_LEAST64_TYPE__ long int
+// AARCH64-OPENBSD:#define __INT_LEAST8_FMTd__ "hhd"
+// AARCH64-OPENBSD:#define __INT_LEAST8_FMTi__ "hhi"
+// AARCH64-OPENBSD:#define __INT_LEAST8_MAX__ 127
+// AARCH64-OPENBSD:#define __INT_LEAST8_TYPE__ signed char
+// AARCH64-OPENBSD:#define __INT_MAX__ 2147483647
+// AARCH64-OPENBSD:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L
+// AARCH64-OPENBSD:#define __LDBL_DIG__ 33
+// AARCH64-OPENBSD:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L
+// AARCH64-OPENBSD:#define __LDBL_HAS_DENORM__ 1
+// AARCH64-OPENBSD:#define __LDBL_HAS_INFINITY__ 1
+// AARCH64-OPENBSD:#define __LDBL_HAS_QUIET_NAN__ 1
+// AARCH64-OPENBSD:#define __LDBL_MANT_DIG__ 113
+// AARCH64-OPENBSD:#define __LDBL_MAX_10_EXP__ 4932
+// AARCH64-OPENBSD:#define __LDBL_MAX_EXP__ 16384
+// AARCH64-OPENBSD:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L
+// AARCH64-OPENBSD:#define __LDBL_MIN_10_EXP__ (-4931)
+// AARCH64-OPENBSD:#define __LDBL_MIN_EXP__ (-16381)
+// AARCH64-OPENBSD:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L
+// AARCH64-OPENBSD:#define __LITTLE_ENDIAN__ 1
+// AARCH64-OPENBSD:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// AARCH64-OPENBSD:#define __LONG_MAX__ 9223372036854775807L
+// AARCH64-OPENBSD:#define __LP64__ 1
+// AARCH64-OPENBSD:#define __OpenBSD__ 1
+// AARCH64-OPENBSD:#define __POINTER_WIDTH__ 64
+// AARCH64-OPENBSD:#define __PTRDIFF_TYPE__ long int
+// AARCH64-OPENBSD:#define __PTRDIFF_WIDTH__ 64
+// AARCH64-OPENBSD:#define __SCHAR_MAX__ 127
+// AARCH64-OPENBSD:#define __SHRT_MAX__ 32767
+// AARCH64-OPENBSD:#define __SIG_ATOMIC_MAX__ 2147483647
+// AARCH64-OPENBSD:#define __SIG_ATOMIC_WIDTH__ 32
+// AARCH64-OPENBSD:#define __SIZEOF_DOUBLE__ 8
+// AARCH64-OPENBSD:#define __SIZEOF_FLOAT__ 4
+// AARCH64-OPENBSD:#define __SIZEOF_INT__ 4
+// AARCH64-OPENBSD:#define __SIZEOF_LONG_DOUBLE__ 16
+// AARCH64-OPENBSD:#define __SIZEOF_LONG_LONG__ 8
+// AARCH64-OPENBSD:#define __SIZEOF_LONG__ 8
+// AARCH64-OPENBSD:#define __SIZEOF_POINTER__ 8
+// AARCH64-OPENBSD:#define __SIZEOF_PTRDIFF_T__ 8
+// AARCH64-OPENBSD:#define __SIZEOF_SHORT__ 2
+// AARCH64-OPENBSD:#define __SIZEOF_SIZE_T__ 8
+// AARCH64-OPENBSD:#define __SIZEOF_WCHAR_T__ 4
+// AARCH64-OPENBSD:#define __SIZEOF_WINT_T__ 4
+// AARCH64-OPENBSD:#define __SIZE_MAX__ 18446744073709551615UL
+// AARCH64-OPENBSD:#define __SIZE_TYPE__ long unsigned int
+// AARCH64-OPENBSD:#define __SIZE_WIDTH__ 64
+// AARCH64-OPENBSD:#define __UINT16_C_SUFFIX__
+// AARCH64-OPENBSD:#define __UINT16_MAX__ 65535
+// AARCH64-OPENBSD:#define __UINT16_TYPE__ unsigned short
+// AARCH64-OPENBSD:#define __UINT32_C_SUFFIX__ U
+// AARCH64-OPENBSD:#define __UINT32_MAX__ 4294967295U
+// AARCH64-OPENBSD:#define __UINT32_TYPE__ unsigned int
+// AARCH64-OPENBSD:#define __UINT64_C_SUFFIX__ ULL
+// AARCH64-OPENBSD:#define __UINT64_MAX__ 18446744073709551615ULL
+// AARCH64-OPENBSD:#define __UINT64_TYPE__ long long unsigned int
+// AARCH64-OPENBSD:#define __UINT8_C_SUFFIX__
+// AARCH64-OPENBSD:#define __UINT8_MAX__ 255
+// AARCH64-OPENBSD:#define __UINT8_TYPE__ unsigned char
+// AARCH64-OPENBSD:#define __UINTMAX_C_SUFFIX__ ULL
+// AARCH64-OPENBSD:#define __UINTMAX_MAX__ 18446744073709551615ULL
+// AARCH64-OPENBSD:#define __UINTMAX_TYPE__ long long unsigned int
+// AARCH64-OPENBSD:#define __UINTMAX_WIDTH__ 64
+// AARCH64-OPENBSD:#define __UINTPTR_MAX__ 18446744073709551615UL
+// AARCH64-OPENBSD:#define __UINTPTR_TYPE__ long unsigned int
+// AARCH64-OPENBSD:#define __UINTPTR_WIDTH__ 64
+// AARCH64-OPENBSD:#define __UINT_FAST16_MAX__ 65535
+// AARCH64-OPENBSD:#define __UINT_FAST16_TYPE__ unsigned short
+// AARCH64-OPENBSD:#define __UINT_FAST32_MAX__ 4294967295U
+// AARCH64-OPENBSD:#define __UINT_FAST32_TYPE__ unsigned int
+// AARCH64-OPENBSD:#define __UINT_FAST64_MAX__ 18446744073709551615UL
+// AARCH64-OPENBSD:#define __UINT_FAST64_TYPE__ long unsigned int
+// AARCH64-OPENBSD:#define __UINT_FAST8_MAX__ 255
+// AARCH64-OPENBSD:#define __UINT_FAST8_TYPE__ unsigned char
+// AARCH64-OPENBSD:#define __UINT_LEAST16_MAX__ 65535
+// AARCH64-OPENBSD:#define __UINT_LEAST16_TYPE__ unsigned short
+// AARCH64-OPENBSD:#define __UINT_LEAST32_MAX__ 4294967295U
+// AARCH64-OPENBSD:#define __UINT_LEAST32_TYPE__ unsigned int
+// AARCH64-OPENBSD:#define __UINT_LEAST64_MAX__ 18446744073709551615UL
+// AARCH64-OPENBSD:#define __UINT_LEAST64_TYPE__ long unsigned int
+// AARCH64-OPENBSD:#define __UINT_LEAST8_MAX__ 255
+// AARCH64-OPENBSD:#define __UINT_LEAST8_TYPE__ unsigned char
+// AARCH64-OPENBSD:#define __USER_LABEL_PREFIX__
+// AARCH64-OPENBSD:#define __WCHAR_MAX__ 2147483647
+// AARCH64-OPENBSD:#define __WCHAR_TYPE__ int
+// AARCH64-OPENBSD:#define __WCHAR_WIDTH__ 32
+// AARCH64-OPENBSD:#define __WINT_TYPE__ int
+// AARCH64-OPENBSD:#define __WINT_WIDTH__ 32
+// AARCH64-OPENBSD:#define __aarch64__ 1
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-freebsd11 < /dev/null | FileCheck -match-full-lines -check-prefix AARCH64-FREEBSD %s
//
// AARCH64-FREEBSD:#define _LP64 1
@@ -3040,6 +3232,7 @@
// MIPS32BE:#define __llvm__ 1
// MIPS32BE:#define __mips 32
// MIPS32BE:#define __mips__ 1
+// MIPS32BE:#define __mips_abicalls 1
// MIPS32BE:#define __mips_fpr 32
// MIPS32BE:#define __mips_hard_float 1
// MIPS32BE:#define __mips_o32 1
@@ -3246,6 +3439,7 @@
// MIPS32EL:#define __llvm__ 1
// MIPS32EL:#define __mips 32
// MIPS32EL:#define __mips__ 1
+// MIPS32EL:#define __mips_abicalls 1
// MIPS32EL:#define __mips_fpr 32
// MIPS32EL:#define __mips_hard_float 1
// MIPS32EL:#define __mips_o32 1
@@ -3555,6 +3749,7 @@
// MIPSN32BE: #define __mips64 1
// MIPSN32BE: #define __mips64__ 1
// MIPSN32BE: #define __mips__ 1
+// MIPSN32BE: #define __mips_abicalls 1
// MIPSN32BE: #define __mips_fpr 64
// MIPSN32BE: #define __mips_hard_float 1
// MIPSN32BE: #define __mips_isa_rev 2
@@ -3861,6 +4056,7 @@
// MIPSN32EL: #define __mips64 1
// MIPSN32EL: #define __mips64__ 1
// MIPSN32EL: #define __mips__ 1
+// MIPSN32EL: #define __mips_abicalls 1
// MIPSN32EL: #define __mips_fpr 64
// MIPSN32EL: #define __mips_hard_float 1
// MIPSN32EL: #define __mips_isa_rev 2
@@ -4073,6 +4269,7 @@
// MIPS64BE:#define __mips64 1
// MIPS64BE:#define __mips64__ 1
// MIPS64BE:#define __mips__ 1
+// MIPS64BE:#define __mips_abicalls 1
// MIPS64BE:#define __mips_fpr 64
// MIPS64BE:#define __mips_hard_float 1
// MIPS64BE:#define __mips_n64 1
@@ -4282,6 +4479,7 @@
// MIPS64EL:#define __mips64 1
// MIPS64EL:#define __mips64__ 1
// MIPS64EL:#define __mips__ 1
+// MIPS64EL:#define __mips_abicalls 1
// MIPS64EL:#define __mips_fpr 64
// MIPS64EL:#define __mips_hard_float 1
// MIPS64EL:#define __mips_n64 1
@@ -4513,6 +4711,45 @@
// MIPS-XXR6:#define __mips_fpr 64
// MIPS-XXR6:#define __mips_nan2008 1
//
+// RUN: %clang_cc1 -target-cpu mips32 \
+// RUN: -E -dM -triple=mips-unknown-netbsd -mrelocation-model pic < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix MIPS-ABICALLS-NETBSD %s
+// MIPS-ABICALLS-NETBSD-NOT: #define __ABICALLS__ 1
+// MIPS-ABICALLS-NETBSD: #define __mips_abicalls 1
+//
+// RUN: %clang_cc1 -target-cpu mips64 \
+// RUN: -E -dM -triple=mips64-unknown-netbsd -mrelocation-model pic < \
+// RUN: /dev/null | FileCheck -match-full-lines \
+// RUN: -check-prefix MIPS-ABICALLS-NETBSD64 %s
+// MIPS-ABICALLS-NETBSD64-NOT: #define __ABICALLS__ 1
+// MIPS-ABICALLS-NETBSD64: #define __mips_abicalls 1
+//
+// RUN: %clang_cc1 -target-cpu mips32 \
+// RUN: -E -dM -triple=mips-unknown-freebsd -mrelocation-model pic < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix MIPS-ABICALLS-FREEBSD %s
+// MIPS-ABICALLS-FREEBSD: #define __ABICALLS__ 1
+// MIPS-ABICALLS-FREEBSD: #define __mips_abicalls 1
+//
+// RUN: %clang_cc1 -target-cpu mips64 \
+// RUN: -E -dM -triple=mips64-unknown-freebsd -mrelocation-model pic < \
+// RUN: /dev/null | FileCheck -match-full-lines \
+// RUN: -check-prefix MIPS-ABICALLS-FREEBSD64 %s
+// MIPS-ABICALLS-FREEBSD64: #define __ABICALLS__ 1
+// MIPS-ABICALLS-FREEBSD64: #define __mips_abicalls 1
+//
+// RUN: %clang_cc1 -target-cpu mips32 \
+// RUN: -E -dM -triple=mips-unknown-openbsd -mrelocation-model pic < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix MIPS-ABICALLS-OPENBSD %s
+// MIPS-ABICALLS-OPENBSD: #define __ABICALLS__ 1
+// MIPS-ABICALLS-OPENBSD: #define __mips_abicalls 1
+//
+// RUN: %clang_cc1 -target-cpu mips64 \
+// RUN: -E -dM -triple=mips64-unknown-openbsd -mrelocation-model pic < \
+// RUN: /dev/null | FileCheck -match-full-lines \
+// RUN: -check-prefix MIPS-ABICALLS-OPENBSD64 %s
+// MIPS-ABICALLS-OPENBSD64: #define __ABICALLS__ 1
+// MIPS-ABICALLS-OPENBSD64: #define __mips_abicalls 1
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=msp430-none-none < /dev/null | FileCheck -match-full-lines -check-prefix MSP430 %s
// RUN: %clang_cc1 -x c++ -E -dM -ffreestanding -triple=msp430-none-none < /dev/null | FileCheck -match-full-lines -check-prefix MSP430 -check-prefix MSP430-CXX %s
//
@@ -5087,7 +5324,7 @@
// PPC603E:#define _ARCH_PPCGR 1
// PPC603E:#define _BIG_ENDIAN 1
// PPC603E-NOT:#define _LP64
-// PPC603E:#define __BIGGEST_ALIGNMENT__ 8
+// PPC603E:#define __BIGGEST_ALIGNMENT__ 16
// PPC603E:#define __BIG_ENDIAN__ 1
// PPC603E:#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
// PPC603E:#define __CHAR16_TYPE__ unsigned short
@@ -5199,6 +5436,7 @@
// PPC603E:#define __LDBL_MIN_10_EXP__ (-291)
// PPC603E:#define __LDBL_MIN_EXP__ (-968)
// PPC603E:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC603E:#define __LONGDOUBLE128 1
// PPC603E:#define __LONG_DOUBLE_128__ 1
// PPC603E:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC603E:#define __LONG_MAX__ 2147483647L
@@ -5287,7 +5525,7 @@
// PPC64:#define _ARCH_PWR7 1
// PPC64:#define _BIG_ENDIAN 1
// PPC64:#define _LP64 1
-// PPC64:#define __BIGGEST_ALIGNMENT__ 8
+// PPC64:#define __BIGGEST_ALIGNMENT__ 16
// PPC64:#define __BIG_ENDIAN__ 1
// PPC64:#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
// PPC64:#define __CHAR16_TYPE__ unsigned short
@@ -5323,6 +5561,7 @@
// PPC64:#define __FLT_MIN_EXP__ (-125)
// PPC64:#define __FLT_MIN__ 1.17549435e-38F
// PPC64:#define __FLT_RADIX__ 2
+// PPC64:#define __HAVE_BSWAP__ 1
// PPC64:#define __INT16_C_SUFFIX__
// PPC64:#define __INT16_FMTd__ "hd"
// PPC64:#define __INT16_FMTi__ "hi"
@@ -5400,6 +5639,7 @@
// PPC64:#define __LDBL_MIN_10_EXP__ (-291)
// PPC64:#define __LDBL_MIN_EXP__ (-968)
// PPC64:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC64:#define __LONGDOUBLE128 1
// PPC64:#define __LONG_DOUBLE_128__ 1
// PPC64:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC64:#define __LONG_MAX__ 9223372036854775807L
@@ -5491,7 +5731,7 @@
// PPC64LE:#define _CALL_ELF 2
// PPC64LE:#define _LITTLE_ENDIAN 1
// PPC64LE:#define _LP64 1
-// PPC64LE:#define __BIGGEST_ALIGNMENT__ 8
+// PPC64LE:#define __BIGGEST_ALIGNMENT__ 16
// PPC64LE:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
// PPC64LE:#define __CHAR16_TYPE__ unsigned short
// PPC64LE:#define __CHAR32_TYPE__ unsigned int
@@ -5526,6 +5766,7 @@
// PPC64LE:#define __FLT_MIN_EXP__ (-125)
// PPC64LE:#define __FLT_MIN__ 1.17549435e-38F
// PPC64LE:#define __FLT_RADIX__ 2
+// PPC64LE:#define __HAVE_BSWAP__ 1
// PPC64LE:#define __INT16_C_SUFFIX__
// PPC64LE:#define __INT16_FMTd__ "hd"
// PPC64LE:#define __INT16_FMTi__ "hi"
@@ -5604,6 +5845,7 @@
// PPC64LE:#define __LDBL_MIN_EXP__ (-968)
// PPC64LE:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
// PPC64LE:#define __LITTLE_ENDIAN__ 1
+// PPC64LE:#define __LONGDOUBLE128 1
// PPC64LE:#define __LONG_DOUBLE_128__ 1
// PPC64LE:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC64LE:#define __LONG_MAX__ 9223372036854775807L
@@ -5635,6 +5877,7 @@
// PPC64LE:#define __SIZE_MAX__ 18446744073709551615UL
// PPC64LE:#define __SIZE_TYPE__ long unsigned int
// PPC64LE:#define __SIZE_WIDTH__ 64
+// PPC64LE:#define __STRUCT_PARM_ALIGN__ 16
// PPC64LE:#define __UINT16_C_SUFFIX__
// PPC64LE:#define __UINT16_MAX__ 65535
// PPC64LE:#define __UINT16_TYPE__ unsigned short
@@ -5855,6 +6098,9 @@
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu power8 -fno-signed-char < /dev/null | FileCheck -match-full-lines -check-prefix PPCPOWER8 %s
//
+// ppc64le also defaults to power8.
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-none-none -target-cpu ppc64le -fno-signed-char < /dev/null | FileCheck -match-full-lines -check-prefix PPCPOWER8 %s
+//
// PPCPOWER8:#define _ARCH_PPC 1
// PPCPOWER8:#define _ARCH_PPC64 1
// PPCPOWER8:#define _ARCH_PPCGR 1
@@ -5903,8 +6149,9 @@
// PPC64-LINUX:#define _ARCH_PPC 1
// PPC64-LINUX:#define _ARCH_PPC64 1
// PPC64-LINUX:#define _BIG_ENDIAN 1
+// PPC64-LINUX:#define _CALL_LINUX 1
// PPC64-LINUX:#define _LP64 1
-// PPC64-LINUX:#define __BIGGEST_ALIGNMENT__ 8
+// PPC64-LINUX:#define __BIGGEST_ALIGNMENT__ 16
// PPC64-LINUX:#define __BIG_ENDIAN__ 1
// PPC64-LINUX:#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
// PPC64-LINUX:#define __CHAR16_TYPE__ unsigned short
@@ -5940,6 +6187,7 @@
// PPC64-LINUX:#define __FLT_MIN_EXP__ (-125)
// PPC64-LINUX:#define __FLT_MIN__ 1.17549435e-38F
// PPC64-LINUX:#define __FLT_RADIX__ 2
+// PPC64-LINUX:#define __HAVE_BSWAP__ 1
// PPC64-LINUX:#define __INT16_C_SUFFIX__
// PPC64-LINUX:#define __INT16_FMTd__ "hd"
// PPC64-LINUX:#define __INT16_FMTi__ "hi"
@@ -6017,6 +6265,7 @@
// PPC64-LINUX:#define __LDBL_MIN_10_EXP__ (-291)
// PPC64-LINUX:#define __LDBL_MIN_EXP__ (-968)
// PPC64-LINUX:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC64-LINUX:#define __LONGDOUBLE128 1
// PPC64-LINUX:#define __LONG_DOUBLE_128__ 1
// PPC64-LINUX:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC64-LINUX:#define __LONG_MAX__ 9223372036854775807L
@@ -6105,12 +6354,17 @@
// PPC64-ELFv1:#define _CALL_ELF 1
// PPC64-ELFv2:#define _CALL_ELF 2
//
+// Most of this is encompassed in other places.
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-unknown-linux-gnu -target-abi elfv2 < /dev/null | FileCheck -match-full-lines -check-prefix PPC64LE-LINUX %s
+//
+// PPC64LE-LINUX:#define _CALL_LINUX 1
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-none-none -fno-signed-char < /dev/null | FileCheck -match-full-lines -check-prefix PPC %s
//
// PPC:#define _ARCH_PPC 1
// PPC:#define _BIG_ENDIAN 1
// PPC-NOT:#define _LP64
-// PPC:#define __BIGGEST_ALIGNMENT__ 8
+// PPC:#define __BIGGEST_ALIGNMENT__ 16
// PPC:#define __BIG_ENDIAN__ 1
// PPC:#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
// PPC:#define __CHAR16_TYPE__ unsigned short
@@ -6146,6 +6400,7 @@
// PPC:#define __FLT_MIN_EXP__ (-125)
// PPC:#define __FLT_MIN__ 1.17549435e-38F
// PPC:#define __FLT_RADIX__ 2
+// PPC:#define __HAVE_BSWAP__ 1
// PPC:#define __INT16_C_SUFFIX__
// PPC:#define __INT16_FMTd__ "hd"
// PPC:#define __INT16_FMTi__ "hi"
@@ -6223,6 +6478,7 @@
// PPC:#define __LDBL_MIN_10_EXP__ (-291)
// PPC:#define __LDBL_MIN_EXP__ (-968)
// PPC:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC:#define __LONGDOUBLE128 1
// PPC:#define __LONG_DOUBLE_128__ 1
// PPC:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC:#define __LONG_MAX__ 2147483647L
@@ -6301,7 +6557,7 @@
// PPC-LINUX:#define _ARCH_PPC 1
// PPC-LINUX:#define _BIG_ENDIAN 1
// PPC-LINUX-NOT:#define _LP64
-// PPC-LINUX:#define __BIGGEST_ALIGNMENT__ 8
+// PPC-LINUX:#define __BIGGEST_ALIGNMENT__ 16
// PPC-LINUX:#define __BIG_ENDIAN__ 1
// PPC-LINUX:#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
// PPC-LINUX:#define __CHAR16_TYPE__ unsigned short
@@ -6337,6 +6593,7 @@
// PPC-LINUX:#define __FLT_MIN_EXP__ (-125)
// PPC-LINUX:#define __FLT_MIN__ 1.17549435e-38F
// PPC-LINUX:#define __FLT_RADIX__ 2
+// PPC-LINUX:#define __HAVE_BSWAP__ 1
// PPC-LINUX:#define __INT16_C_SUFFIX__
// PPC-LINUX:#define __INT16_FMTd__ "hd"
// PPC-LINUX:#define __INT16_FMTi__ "hi"
@@ -6414,6 +6671,7 @@
// PPC-LINUX:#define __LDBL_MIN_10_EXP__ (-291)
// PPC-LINUX:#define __LDBL_MIN_EXP__ (-968)
// PPC-LINUX:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC-LINUX:#define __LONGDOUBLE128 1
// PPC-LINUX:#define __LONG_DOUBLE_128__ 1
// PPC-LINUX:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC-LINUX:#define __LONG_MAX__ 2147483647L
@@ -6489,6 +6747,10 @@
// PPC-LINUX:#define __powerpc__ 1
// PPC-LINUX:#define __ppc__ 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-unknown-linux-gnu -fno-signed-char < /dev/null | FileCheck -match-full-lines -check-prefix PPC32-LINUX %s
+//
+// PPC32-LINUX-NOT: _CALL_LINUX
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-apple-darwin8 < /dev/null | FileCheck -match-full-lines -check-prefix PPC-DARWIN %s
//
// PPC-DARWIN:#define _ARCH_PPC 1
@@ -6528,6 +6790,7 @@
// PPC-DARWIN:#define __FLT_MIN_EXP__ (-125)
// PPC-DARWIN:#define __FLT_MIN__ 1.17549435e-38F
// PPC-DARWIN:#define __FLT_RADIX__ 2
+// PPC-DARWIN:#define __HAVE_BSWAP__ 1
// PPC-DARWIN:#define __INT16_C_SUFFIX__
// PPC-DARWIN:#define __INT16_FMTd__ "hd"
// PPC-DARWIN:#define __INT16_FMTi__ "hi"
@@ -6605,6 +6868,7 @@
// PPC-DARWIN:#define __LDBL_MIN_10_EXP__ (-291)
// PPC-DARWIN:#define __LDBL_MIN_EXP__ (-968)
// PPC-DARWIN:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC-DARWIN:#define __LONGDOUBLE128 1
// PPC-DARWIN:#define __LONG_DOUBLE_128__ 1
// PPC-DARWIN:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC-DARWIN:#define __LONG_MAX__ 2147483647L
@@ -6684,7 +6948,10 @@
// PPC-DARWIN:#define __WINT_WIDTH__ 32
// PPC-DARWIN:#define __powerpc__ 1
// PPC-DARWIN:#define __ppc__ 1
-//
+
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-apple-darwin8 < /dev/null | FileCheck -match-full-lines -check-prefix PPC64-DARWIN %s
+// PPC64-DARWIN:#define __STRUCT_PARM_ALIGN__ 16
+
// RUN: %clang_cc1 -x cl -E -dM -ffreestanding -triple=amdgcn < /dev/null | FileCheck -match-full-lines -check-prefix AMDGCN --check-prefix AMDGPU %s
// RUN: %clang_cc1 -x cl -E -dM -ffreestanding -triple=r600 -target-cpu caicos < /dev/null | FileCheck -match-full-lines --check-prefix AMDGPU %s
//
@@ -8466,6 +8733,7 @@
// PS4:#define __unix__ 1
// PS4:#define __x86_64 1
// PS4:#define __x86_64__ 1
+// PS4:#define unix 1
//
// RUN: %clang_cc1 -E -dM -triple=x86_64-pc-mingw32 < /dev/null | FileCheck -match-full-lines -check-prefix X86-64-DECLSPEC %s
// RUN: %clang_cc1 -E -dM -fms-extensions -triple=x86_64-unknown-mingw32 < /dev/null | FileCheck -match-full-lines -check-prefix X86-64-DECLSPEC %s
@@ -8523,8 +8791,12 @@
// LANAI: #define __lanai__ 1
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=amd64-unknown-openbsd6.1 < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-unknown-openbsd6.1 < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD %s
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-unknown-openbsd6.1-gnueabi < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD %s
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-unknown-openbsd6.1 < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-unknown-openbsd6.1 < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=mips64-unknown-openbsd6.1 < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=mips64el-unknown-openbsd6.1 < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD %s
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=sparc64-unknown-openbsd6.1 < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD %s
// OPENBSD:#define __ELF__ 1
// OPENBSD:#define __INT16_TYPE__ short
@@ -8705,6 +8977,7 @@
// WEBASSEMBLY32-NEXT:#define __LONG_MAX__ 2147483647L
// WEBASSEMBLY32-NOT:#define __LP64__
// WEBASSEMBLY32-NEXT:#define __NO_INLINE__ 1
+// WEBASSEMBLY32-NEXT:#define __OBJC_BOOL_IS_BOOL 0
// WEBASSEMBLY32-NEXT:#define __ORDER_BIG_ENDIAN__ 4321
// WEBASSEMBLY32-NEXT:#define __ORDER_LITTLE_ENDIAN__ 1234
// WEBASSEMBLY32-NEXT:#define __ORDER_PDP_ENDIAN__ 3412
@@ -9020,6 +9293,7 @@
// WEBASSEMBLY64-NEXT:#define __LONG_MAX__ 9223372036854775807L
// WEBASSEMBLY64-NEXT:#define __LP64__ 1
// WEBASSEMBLY64-NEXT:#define __NO_INLINE__ 1
+// WEBASSEMBLY64-NEXT:#define __OBJC_BOOL_IS_BOOL 0
// WEBASSEMBLY64-NEXT:#define __ORDER_BIG_ENDIAN__ 4321
// WEBASSEMBLY64-NEXT:#define __ORDER_LITTLE_ENDIAN__ 1234
// WEBASSEMBLY64-NEXT:#define __ORDER_PDP_ENDIAN__ 3412
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 883cc4d19b29..a0eb8cbcca9a 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -525,7 +525,6 @@
// CHECK_CORE_AVX2_M32: #define __PCLMUL__ 1
// CHECK_CORE_AVX2_M32: #define __POPCNT__ 1
// CHECK_CORE_AVX2_M32: #define __RDRND__ 1
-// CHECK_CORE_AVX2_M32: #define __RTM__ 1
// CHECK_CORE_AVX2_M32: #define __SSE2__ 1
// CHECK_CORE_AVX2_M32: #define __SSE3__ 1
// CHECK_CORE_AVX2_M32: #define __SSE4_1__ 1
@@ -555,7 +554,6 @@
// CHECK_CORE_AVX2_M64: #define __PCLMUL__ 1
// CHECK_CORE_AVX2_M64: #define __POPCNT__ 1
// CHECK_CORE_AVX2_M64: #define __RDRND__ 1
-// CHECK_CORE_AVX2_M64: #define __RTM__ 1
// CHECK_CORE_AVX2_M64: #define __SSE2_MATH__ 1
// CHECK_CORE_AVX2_M64: #define __SSE2__ 1
// CHECK_CORE_AVX2_M64: #define __SSE3__ 1
@@ -591,7 +589,6 @@
// CHECK_BROADWELL_M32: #define __POPCNT__ 1
// CHECK_BROADWELL_M32: #define __RDRND__ 1
// CHECK_BROADWELL_M32: #define __RDSEED__ 1
-// CHECK_BROADWELL_M32: #define __RTM__ 1
// CHECK_BROADWELL_M32: #define __SSE2__ 1
// CHECK_BROADWELL_M32: #define __SSE3__ 1
// CHECK_BROADWELL_M32: #define __SSE4_1__ 1
@@ -623,7 +620,6 @@
// CHECK_BROADWELL_M64: #define __POPCNT__ 1
// CHECK_BROADWELL_M64: #define __RDRND__ 1
// CHECK_BROADWELL_M64: #define __RDSEED__ 1
-// CHECK_BROADWELL_M64: #define __RTM__ 1
// CHECK_BROADWELL_M64: #define __SSE2_MATH__ 1
// CHECK_BROADWELL_M64: #define __SSE2__ 1
// CHECK_BROADWELL_M64: #define __SSE3__ 1
@@ -651,15 +647,18 @@
// CHECK_SKL_M32: #define __AVX__ 1
// CHECK_SKL_M32: #define __BMI2__ 1
// CHECK_SKL_M32: #define __BMI__ 1
+// CHECK_SKL_M32: #define __CLFLUSHOPT__ 1
// CHECK_SKL_M32: #define __F16C__ 1
// CHECK_SKL_M32: #define __FMA__ 1
// CHECK_SKL_M32: #define __LZCNT__ 1
// CHECK_SKL_M32: #define __MMX__ 1
+// CHECK_SKL_M32: #define __MPX__ 1
// CHECK_SKL_M32: #define __PCLMUL__ 1
// CHECK_SKL_M32: #define __POPCNT__ 1
// CHECK_SKL_M32: #define __RDRND__ 1
// CHECK_SKL_M32: #define __RDSEED__ 1
// CHECK_SKL_M32: #define __RTM__ 1
+// CHECK_SKL_M32: #define __SGX__ 1
// CHECK_SKL_M32: #define __SSE2__ 1
// CHECK_SKL_M32: #define __SSE3__ 1
// CHECK_SKL_M32: #define __SSE4_1__ 1
@@ -681,15 +680,18 @@
// CHECK_SKL_M64: #define __AVX__ 1
// CHECK_SKL_M64: #define __BMI2__ 1
// CHECK_SKL_M64: #define __BMI__ 1
+// CHECK_SKL_M64: #define __CLFLUSHOPT__ 1
// CHECK_SKL_M64: #define __F16C__ 1
// CHECK_SKL_M64: #define __FMA__ 1
// CHECK_SKL_M64: #define __LZCNT__ 1
// CHECK_SKL_M64: #define __MMX__ 1
+// CHECK_SKL_M64: #define __MPX__ 1
// CHECK_SKL_M64: #define __PCLMUL__ 1
// CHECK_SKL_M64: #define __POPCNT__ 1
// CHECK_SKL_M64: #define __RDRND__ 1
// CHECK_SKL_M64: #define __RDSEED__ 1
// CHECK_SKL_M64: #define __RTM__ 1
+// CHECK_SKL_M64: #define __SGX__ 1
// CHECK_SKL_M64: #define __SSE2_MATH__ 1
// CHECK_SKL_M64: #define __SSE2__ 1
// CHECK_SKL_M64: #define __SSE3__ 1
@@ -725,6 +727,7 @@
// CHECK_KNL_M32: #define __MMX__ 1
// CHECK_KNL_M32: #define __PCLMUL__ 1
// CHECK_KNL_M32: #define __POPCNT__ 1
+// CHECK_KNL_M32: #define __PREFETCHWT1__ 1
// CHECK_KNL_M32: #define __RDRND__ 1
// CHECK_KNL_M32: #define __RTM__ 1
// CHECK_KNL_M32: #define __SSE2__ 1
@@ -760,6 +763,7 @@
// CHECK_KNL_M64: #define __MMX__ 1
// CHECK_KNL_M64: #define __PCLMUL__ 1
// CHECK_KNL_M64: #define __POPCNT__ 1
+// CHECK_KNL_M64: #define __PREFETCHWT1__ 1
// CHECK_KNL_M64: #define __RDRND__ 1
// CHECK_KNL_M64: #define __RTM__ 1
// CHECK_KNL_M64: #define __SSE2_MATH__ 1
@@ -793,14 +797,18 @@
// CHECK_SKX_M32: #define __AVX__ 1
// CHECK_SKX_M32: #define __BMI2__ 1
// CHECK_SKX_M32: #define __BMI__ 1
+// CHECK_SKX_M32: #define __CLFLUSHOPT__ 1
+// CHECK_SKX_M32: #define __CLWB__ 1
// CHECK_SKX_M32: #define __F16C__ 1
// CHECK_SKX_M32: #define __FMA__ 1
// CHECK_SKX_M32: #define __LZCNT__ 1
// CHECK_SKX_M32: #define __MMX__ 1
+// CHECK_SKX_M32: #define __MPX__ 1
// CHECK_SKX_M32: #define __PCLMUL__ 1
// CHECK_SKX_M32: #define __POPCNT__ 1
// CHECK_SKX_M32: #define __RDRND__ 1
// CHECK_SKX_M32: #define __RTM__ 1
+// CHECK_SKX_M32: #define __SGX__ 1
// CHECK_SKX_M32: #define __SSE2__ 1
// CHECK_SKX_M32: #define __SSE3__ 1
// CHECK_SKX_M32: #define __SSE4_1__ 1
@@ -831,14 +839,18 @@
// CHECK_SKX_M64: #define __AVX__ 1
// CHECK_SKX_M64: #define __BMI2__ 1
// CHECK_SKX_M64: #define __BMI__ 1
+// CHECK_SKX_M64: #define __CLFLUSHOPT__ 1
+// CHECK_SKX_M64: #define __CLWB__ 1
// CHECK_SKX_M64: #define __F16C__ 1
// CHECK_SKX_M64: #define __FMA__ 1
// CHECK_SKX_M64: #define __LZCNT__ 1
// CHECK_SKX_M64: #define __MMX__ 1
+// CHECK_SKX_M64: #define __MPX__ 1
// CHECK_SKX_M64: #define __PCLMUL__ 1
// CHECK_SKX_M64: #define __POPCNT__ 1
// CHECK_SKX_M64: #define __RDRND__ 1
// CHECK_SKX_M64: #define __RTM__ 1
+// CHECK_SKX_M64: #define __SGX__ 1
// CHECK_SKX_M64: #define __SSE2_MATH__ 1
// CHECK_SKX_M64: #define __SSE2__ 1
// CHECK_SKX_M64: #define __SSE3__ 1
@@ -874,14 +886,17 @@
// CHECK_CNL_M32: #define __AVX__ 1
// CHECK_CNL_M32: #define __BMI2__ 1
// CHECK_CNL_M32: #define __BMI__ 1
+// CHECK_CNL_M32: #define __CLFLUSHOPT__ 1
// CHECK_CNL_M32: #define __F16C__ 1
// CHECK_CNL_M32: #define __FMA__ 1
// CHECK_CNL_M32: #define __LZCNT__ 1
// CHECK_CNL_M32: #define __MMX__ 1
+// CHECK_CNL_M32: #define __MPX__ 1
// CHECK_CNL_M32: #define __PCLMUL__ 1
// CHECK_CNL_M32: #define __POPCNT__ 1
// CHECK_CNL_M32: #define __RDRND__ 1
// CHECK_CNL_M32: #define __RTM__ 1
+// CHECK_CNL_M32: #define __SGX__ 1
// CHECK_CNL_M32: #define __SHA__ 1
// CHECK_CNL_M32: #define __SSE2__ 1
// CHECK_CNL_M32: #define __SSE3__ 1
@@ -912,14 +927,17 @@
// CHECK_CNL_M64: #define __AVX__ 1
// CHECK_CNL_M64: #define __BMI2__ 1
// CHECK_CNL_M64: #define __BMI__ 1
+// CHECK_CNL_M64: #define __CLFLUSHOPT__ 1
// CHECK_CNL_M64: #define __F16C__ 1
// CHECK_CNL_M64: #define __FMA__ 1
// CHECK_CNL_M64: #define __LZCNT__ 1
// CHECK_CNL_M64: #define __MMX__ 1
+// CHECK_CNL_M64: #define __MPX__ 1
// CHECK_CNL_M64: #define __PCLMUL__ 1
// CHECK_CNL_M64: #define __POPCNT__ 1
// CHECK_CNL_M64: #define __RDRND__ 1
// CHECK_CNL_M64: #define __RTM__ 1
+// CHECK_CNL_M64: #define __SGX__ 1
// CHECK_CNL_M64: #define __SHA__ 1
// CHECK_CNL_M64: #define __SSE2__ 1
// CHECK_CNL_M64: #define __SSE3__ 1
@@ -1860,6 +1878,8 @@
// CHECK_ZNVER1_M32: #define __AVX__ 1
// CHECK_ZNVER1_M32: #define __BMI2__ 1
// CHECK_ZNVER1_M32: #define __BMI__ 1
+// CHECK_ZNVER1_M32: #define __CLFLUSHOPT__ 1
+// CHECK_ZNVER1_M32: #define __CLZERO__ 1
// CHECK_ZNVER1_M32: #define __F16C__ 1
// CHECK_ZNVER1_M32: #define __FMA__ 1
// CHECK_ZNVER1_M32: #define __FSGSBASE__ 1
@@ -1900,6 +1920,8 @@
// CHECK_ZNVER1_M64: #define __AVX__ 1
// CHECK_ZNVER1_M64: #define __BMI2__ 1
// CHECK_ZNVER1_M64: #define __BMI__ 1
+// CHECK_ZNVER1_M64: #define __CLFLUSHOPT__ 1
+// CHECK_ZNVER1_M64: #define __CLZERO__ 1
// CHECK_ZNVER1_M64: #define __F16C__ 1
// CHECK_ZNVER1_M64: #define __FMA__ 1
// CHECK_ZNVER1_M64: #define __FSGSBASE__ 1
@@ -1935,6 +1957,14 @@
// End X86/GCC/Linux tests ------------------
// Begin PPC/GCC/Linux tests ----------------
+// Check that VSX also turns on altivec.
+// RUN: %clang -mvsx -E -dM %s -o - 2>&1 \
+// RUN: -target powerpc-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_PPC_VSX_M32
+//
+// CHECK_PPC_VSX_M32: #define __ALTIVEC__ 1
+// CHECK_PPC_VSX_M32: #define __VSX__ 1
+//
// RUN: %clang -mvsx -E -dM %s -o - 2>&1 \
// RUN: -target powerpc64-unknown-linux \
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_PPC_VSX_M64
@@ -1958,6 +1988,24 @@
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_PPC_CRYPTO_M64
//
// CHECK_PPC_CRYPTO_M64: #define __CRYPTO__ 1
+
+// HTM is available on power8 or later which includes all of powerpc64le as an
+// ABI choice. Test that, the cpus, and the option.
+// RUN: %clang -mhtm -E -dM %s -o - 2>&1 \
+// RUN: -target powerpc64-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_PPC_HTM
+// RUN: %clang -E -dM %s -o - 2>&1 \
+// RUN: -target powerpc64le-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_PPC_HTM
+// RUN: %clang -mcpu=pwr8 -E -dM %s -o - 2>&1 \
+// RUN: -target powerpc64-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_PPC_HTM
+// RUN: %clang -mcpu=pwr9 -E -dM %s -o - 2>&1 \
+// RUN: -target powerpc64-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_PPC_HTM
+//
+// CHECK_PPC_HTM: #define __HTM__ 1
+
//
// RUN: %clang -mcpu=ppc64 -E -dM %s -o - 2>&1 \
// RUN: -target powerpc64-unknown-unknown \
@@ -2035,35 +2083,76 @@
// Begin SystemZ/GCC/Linux tests ----------------
//
+// RUN: %clang -march=arch8 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH8
// RUN: %clang -march=z10 -E -dM %s -o - 2>&1 \
// RUN: -target s390x-unknown-linux \
-// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_Z10
-//
-// CHECK_SYSTEMZ_Z10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
-// CHECK_SYSTEMZ_Z10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
-// CHECK_SYSTEMZ_Z10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
-// CHECK_SYSTEMZ_Z10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
-// CHECK_SYSTEMZ_Z10: #define __LONG_DOUBLE_128__ 1
-// CHECK_SYSTEMZ_Z10: #define __s390__ 1
-// CHECK_SYSTEMZ_Z10: #define __s390x__ 1
-// CHECK_SYSTEMZ_Z10: #define __zarch__ 1
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH8
+//
+// CHECK_SYSTEMZ_ARCH8: #define __ARCH__ 8
+// CHECK_SYSTEMZ_ARCH8: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
+// CHECK_SYSTEMZ_ARCH8: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
+// CHECK_SYSTEMZ_ARCH8: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
+// CHECK_SYSTEMZ_ARCH8: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
+// CHECK_SYSTEMZ_ARCH8: #define __LONG_DOUBLE_128__ 1
+// CHECK_SYSTEMZ_ARCH8: #define __s390__ 1
+// CHECK_SYSTEMZ_ARCH8: #define __s390x__ 1
+// CHECK_SYSTEMZ_ARCH8: #define __zarch__ 1
+//
+// RUN: %clang -march=arch9 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH9
+// RUN: %clang -march=z196 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH9
+//
+// CHECK_SYSTEMZ_ARCH9: #define __ARCH__ 9
+// CHECK_SYSTEMZ_ARCH9: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
+// CHECK_SYSTEMZ_ARCH9: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
+// CHECK_SYSTEMZ_ARCH9: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
+// CHECK_SYSTEMZ_ARCH9: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
+// CHECK_SYSTEMZ_ARCH9: #define __LONG_DOUBLE_128__ 1
+// CHECK_SYSTEMZ_ARCH9: #define __s390__ 1
+// CHECK_SYSTEMZ_ARCH9: #define __s390x__ 1
+// CHECK_SYSTEMZ_ARCH9: #define __zarch__ 1
//
+// RUN: %clang -march=arch10 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH10
// RUN: %clang -march=zEC12 -E -dM %s -o - 2>&1 \
// RUN: -target s390x-unknown-linux \
-// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ZEC12
-// RUN: %clang -march=arch10 -E -dM %s -o - 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH10
+//
+// CHECK_SYSTEMZ_ARCH10: #define __ARCH__ 10
+// CHECK_SYSTEMZ_ARCH10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
+// CHECK_SYSTEMZ_ARCH10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
+// CHECK_SYSTEMZ_ARCH10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
+// CHECK_SYSTEMZ_ARCH10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
+// CHECK_SYSTEMZ_ARCH10: #define __HTM__ 1
+// CHECK_SYSTEMZ_ARCH10: #define __LONG_DOUBLE_128__ 1
+// CHECK_SYSTEMZ_ARCH10: #define __s390__ 1
+// CHECK_SYSTEMZ_ARCH10: #define __s390x__ 1
+// CHECK_SYSTEMZ_ARCH10: #define __zarch__ 1
+//
+// RUN: %clang -march=arch11 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH11
+// RUN: %clang -march=z13 -E -dM %s -o - 2>&1 \
// RUN: -target s390x-unknown-linux \
-// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ZEC12
-//
-// CHECK_SYSTEMZ_ZEC12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
-// CHECK_SYSTEMZ_ZEC12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
-// CHECK_SYSTEMZ_ZEC12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
-// CHECK_SYSTEMZ_ZEC12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
-// CHECK_SYSTEMZ_ZEC12: #define __HTM__ 1
-// CHECK_SYSTEMZ_ZEC12: #define __LONG_DOUBLE_128__ 1
-// CHECK_SYSTEMZ_ZEC12: #define __s390__ 1
-// CHECK_SYSTEMZ_ZEC12: #define __s390x__ 1
-// CHECK_SYSTEMZ_ZEC12: #define __zarch__ 1
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH11
+//
+// CHECK_SYSTEMZ_ARCH11: #define __ARCH__ 11
+// CHECK_SYSTEMZ_ARCH11: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
+// CHECK_SYSTEMZ_ARCH11: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
+// CHECK_SYSTEMZ_ARCH11: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
+// CHECK_SYSTEMZ_ARCH11: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
+// CHECK_SYSTEMZ_ARCH11: #define __HTM__ 1
+// CHECK_SYSTEMZ_ARCH11: #define __LONG_DOUBLE_128__ 1
+// CHECK_SYSTEMZ_ARCH11: #define __VX__ 1
+// CHECK_SYSTEMZ_ARCH11: #define __s390__ 1
+// CHECK_SYSTEMZ_ARCH11: #define __s390x__ 1
+// CHECK_SYSTEMZ_ARCH11: #define __zarch__ 1
//
// RUN: %clang -mhtm -E -dM %s -o - 2>&1 \
// RUN: -target s390x-unknown-linux \
@@ -2071,6 +2160,12 @@
//
// CHECK_SYSTEMZ_HTM: #define __HTM__ 1
//
+// RUN: %clang -mvx -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_VX
+//
+// CHECK_SYSTEMZ_VX: #define __VX__ 1
+//
// RUN: %clang -fzvector -E -dM %s -o - 2>&1 \
// RUN: -target s390x-unknown-linux \
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ZVECTOR
diff --git a/test/Preprocessor/x86_target_features.c b/test/Preprocessor/x86_target_features.c
index 43cf615546b1..a201900ba762 100644
--- a/test/Preprocessor/x86_target_features.c
+++ b/test/Preprocessor/x86_target_features.c
@@ -352,3 +352,7 @@
// NOXSAVE-NOT: #define __XSAVEOPT__ 1
// NOXSAVE-NOT: #define __XSAVE__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=atom -mclflushopt -x c -E -dM -o - %s | FileCheck -match-full-lines --check-prefix=CLFLUSHOPT %s
+
+// CLFLUSHOPT: #define __CLFLUSHOPT__ 1
diff --git a/test/Profile/Inputs/cxx-class.proftext b/test/Profile/Inputs/cxx-class.proftext
index b4645edf9333..77645fbc2066 100644
--- a/test/Profile/Inputs/cxx-class.proftext
+++ b/test/Profile/Inputs/cxx-class.proftext
@@ -39,3 +39,14 @@ _ZN6SimpleC2Ei
100
99
+_ZN7DerivedC1Ev
+10
+2
+100
+99
+
+_ZN7DerivedD2Ev
+10
+2
+100
+99
diff --git a/test/Profile/c-generate.c b/test/Profile/c-generate.c
index 5e5b22e8c30d..1e7a739e04e4 100644
--- a/test/Profile/c-generate.c
+++ b/test/Profile/c-generate.c
@@ -5,7 +5,8 @@
//
// PROF-INSTR-PATH: constant [24 x i8] c"c-generate-test.profraw\00"
//
-// PROF-INSTR-NONE-NOT: @__profn_main
+// PROF-INSTR-NONE-NOT: __llvm_prf
+//
// PROF-INSTR-GARBAGE: invalid PGO instrumentor in argument '-fprofile-instrument=garbage'
int main(void) {
diff --git a/test/Profile/c-ternary.c b/test/Profile/c-ternary.c
new file mode 100644
index 000000000000..af7922fa26fa
--- /dev/null
+++ b/test/Profile/c-ternary.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -x c %s -o - -emit-llvm -fprofile-instrument=clang | FileCheck %s
+
+// PR32019: Clang can lower some ternary operator expressions to select
+// instructions. Make sure we only increment the profile counter for the
+// condition when the condition evaluates to true.
+// CHECK-LABEL: define i32 @f1
+int f1(int x) {
+// CHECK: [[TOBOOL:%.*]] = icmp ne i32 %{{.*}}, 0
+// CHECK-NEXT: [[STEP:%.*]] = zext i1 [[TOBOOL]] to i64
+// CHECK-NEXT: [[COUNTER:%.*]] = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @__profc_f1, i64 0, i64 1)
+// CHECK-NEXT: add i64 [[COUNTER]], [[STEP]]
+// CHECK: [[COND:%.*]] = select i1 [[TOBOOL]], i32 0, i32 1
+ return x ? 0 : 1;
+// CHECK: ret i32 [[COND]]
+}
diff --git a/test/Profile/cxx-class.cpp b/test/Profile/cxx-class.cpp
index dbc9337785e1..ab90d195cdc6 100644
--- a/test/Profile/cxx-class.cpp
+++ b/test/Profile/cxx-class.cpp
@@ -5,6 +5,8 @@
// RUN: FileCheck --input-file=%tgen -check-prefix=DTRGEN %s
// RUN: FileCheck --input-file=%tgen -check-prefix=MTHGEN %s
// RUN: FileCheck --input-file=%tgen -check-prefix=WRPGEN %s
+// RUN: FileCheck --input-file=%tgen -check-prefix=VCTRGEN %s
+// RUN: FileCheck --input-file=%tgen -check-prefix=VDTRGEN %s
// RUN: llvm-profdata merge %S/Inputs/cxx-class.proftext -o %t.profdata
// RUN: %clang_cc1 %s -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -triple %itanium_abi_triple > %tuse
@@ -12,10 +14,12 @@
// RUN: FileCheck --input-file=%tuse -check-prefix=DTRUSE %s
// RUN: FileCheck --input-file=%tuse -check-prefix=MTHUSE %s
// RUN: FileCheck --input-file=%tuse -check-prefix=WRPUSE %s
+// RUN: FileCheck --input-file=%tuse -check-prefix=VCTRUSE %s
+// RUN: FileCheck --input-file=%tuse -check-prefix=VDTRUSE %s
class Simple {
- int Member;
public:
+ int Member;
// CTRGEN-LABEL: define {{.*}} @_ZN6SimpleC2Ei(
// CTRUSE-LABEL: define {{.*}} @_ZN6SimpleC2Ei(
// CTRGEN: store {{.*}} @[[SCC:__profc__ZN6SimpleC2Ei]], i64 0, i64 0
@@ -56,6 +60,35 @@ public:
// MTHUSE: ![[SM1]] = !{!"branch_weights", i32 100, i32 2}
};
+class Derived : virtual public Simple {
+public:
+ // VCTRGEN-LABEL: define {{.*}} @_ZN7DerivedC1Ev(
+ // VCTRUSE-LABEL: define {{.*}} @_ZN7DerivedC1Ev(
+ // VCTRGEN: store {{.*}} @[[SCC:__profc__ZN7DerivedC1Ev]], i64 0, i64 0
+ Derived() : Simple(0) {
+ // VCTRGEN: store {{.*}} @[[SCC]], i64 0, i64 1
+ // VCTRUSE: br {{.*}} !prof ![[SC1:[0-9]+]]
+ if (Member) {}
+ // VCTRGEN-NOT: store {{.*}} @[[SCC]],
+ // VCTRUSE-NOT: br {{.*}} !prof ![0-9]+
+ // VCTRUSE: ret
+ }
+ // VCTRUSE: ![[SC1]] = !{!"branch_weights", i32 100, i32 2}
+
+ // VDTRGEN-LABEL: define {{.*}} @_ZN7DerivedD2Ev(
+ // VDTRUSE-LABEL: define {{.*}} @_ZN7DerivedD2Ev(
+ // VDTRGEN: store {{.*}} @[[SDC:__profc__ZN7DerivedD2Ev]], i64 0, i64 0
+ ~Derived() {
+ // VDTRGEN: store {{.*}} @[[SDC]], i64 0, i64 1
+ // VDTRUSE: br {{.*}} !prof ![[SD1:[0-9]+]]
+ if (Member) {}
+ // VDTRGEN-NOT: store {{.*}} @[[SDC]],
+ // VDTRUSE-NOT: br {{.*}} !prof ![0-9]+
+ // VDTRUSE: ret
+ }
+ // VDTRUSE: ![[SD1]] = !{!"branch_weights", i32 100, i32 2}
+};
+
// WRPGEN-LABEL: define {{.*}} @_Z14simple_wrapperv(
// WRPUSE-LABEL: define {{.*}} @_Z14simple_wrapperv(
// WRPGEN: store {{.*}} @[[SWC:__profc__Z14simple_wrapperv]], i64 0, i64 0
@@ -63,6 +96,7 @@ void simple_wrapper() {
// WRPGEN: store {{.*}} @[[SWC]], i64 0, i64 1
// WRPUSE: br {{.*}} !prof ![[SW1:[0-9]+]]
for (int I = 0; I < 100; ++I) {
+ Derived d;
Simple S(I);
S.method();
}
diff --git a/test/Profile/cxx-structors.cpp b/test/Profile/cxx-structors.cpp
index 73562d39c973..8e0fac163d97 100644
--- a/test/Profile/cxx-structors.cpp
+++ b/test/Profile/cxx-structors.cpp
@@ -1,6 +1,8 @@
// Tests for instrumentation of C++ constructors and destructors.
//
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -x c++ %s -o - -emit-llvm -fprofile-instrument=clang | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -x c++ %s -o %t -emit-llvm -fprofile-instrument=clang
+// RUN: FileCheck %s -input-file=%t -check-prefix=INSTR
+// RUN: FileCheck %s -input-file=%t -check-prefix=NOINSTR
struct Foo {
Foo() {}
@@ -14,19 +16,40 @@ struct Bar : public Foo {
~Bar();
};
+struct Baz : virtual public Foo {
+ Baz() {}
+ Baz(int x) : Foo(x) {}
+ ~Baz();
+};
+
+struct Quux : public Foo {
+ Quux(const char *y, ...) : Foo(0) {}
+};
+
Foo foo;
Foo foo2(1);
Bar bar;
+Baz baz;
+Baz baz2(1);
+Quux qux("fi", "fo", "fum");
// Profile data for complete constructors and destructors must absent.
-// CHECK-NOT: @__profn__ZN3FooC1Ev
-// CHECK-NOT: @__profn__ZN3FooC1Ei
-// CHECK-NOT: @__profn__ZN3FooD1Ev
-// CHECK-NOT: @__profn__ZN3BarC1Ev
-// CHECK-NOT: @__profn__ZN3BarD1Ev
-// CHECK-NOT: @__profc__ZN3FooD1Ev
-// CHECK-NOT: @__profd__ZN3FooD1Ev
+// INSTR: @__profc__ZN3BazC1Ev =
+// INSTR: @__profc__ZN3BazC1Ei =
+// INSTR: @__profc__ZN4QuuxC1EPKcz =
+// INSTR: @__profc_main =
+// INSTR: @__profc__ZN3FooC2Ev =
+// INSTR: @__profc__ZN3FooD2Ev =
+// INSTR: @__profc__ZN3FooC2Ei =
+// INSTR: @__profc__ZN3BarC2Ev =
+
+// NOINSTR-NOT: @__profc__ZN3FooC1Ev
+// NOINSTR-NOT: @__profc__ZN3FooC1Ei
+// NOINSTR-NOT: @__profc__ZN3FooD1Ev
+// NOINSTR-NOT: @__profc__ZN3BarC1Ev
+// NOINSTR-NOT: @__profc__ZN3BarD1Ev
+// NOINSTR-NOT: @__profc__ZN3FooD1Ev
int main() {
}
diff --git a/test/Profile/cxx-virtual-destructor-calls.cpp b/test/Profile/cxx-virtual-destructor-calls.cpp
index cc3df68d3569..c60fc921e5bf 100644
--- a/test/Profile/cxx-virtual-destructor-calls.cpp
+++ b/test/Profile/cxx-virtual-destructor-calls.cpp
@@ -13,15 +13,6 @@ struct B : A {
virtual ~B();
};
-// Base dtor
-// CHECK: @__profn__ZN1BD2Ev = private constant [9 x i8] c"_ZN1BD2Ev"
-
-// Complete dtor must not be instrumented
-// CHECK-NOT: @__profn__ZN1BD1Ev = private constant [9 x i8] c"_ZN1BD1Ev"
-
-// Deleting dtor must not be instrumented
-// CHECK-NOT: @__profn__ZN1BD0Ev = private constant [9 x i8] c"_ZN1BD0Ev"
-
// Base dtor counters and profile data
// CHECK: @__profc__ZN1BD2Ev = private global [1 x i64] zeroinitializer
// CHECK: @__profd__ZN1BD2Ev =
diff --git a/test/Rewriter/lit.local.cfg b/test/Rewriter/lit.local.cfg
index 69b733b2e4a3..f5e1d0349f52 100644
--- a/test/Rewriter/lit.local.cfg
+++ b/test/Rewriter/lit.local.cfg
@@ -1,3 +1,3 @@
# The Objective-C rewriters are currently grouped with ARCMT.
-if config.root.clang_arcmt == 0:
+if not config.root.clang_arcmt:
config.unsupported = True
diff --git a/test/Sema/address-unaligned.c b/test/Sema/address-unaligned.c
new file mode 100644
index 000000000000..6719509051b3
--- /dev/null
+++ b/test/Sema/address-unaligned.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify %s
+// expected-no-diagnostics
+
+typedef
+struct __attribute__((packed)) S1 {
+ char c0;
+ int x;
+ char c1;
+} S1;
+
+void bar(__unaligned int *);
+
+void foo(__unaligned S1* s1)
+{
+ bar(&s1->x);
+}
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
index 3fe93155451f..018a8521bfc5 100644
--- a/test/Sema/address_spaces.c
+++ b/test/Sema/address_spaces.c
@@ -20,7 +20,7 @@ void foo(_AS3 float *a,
_AS1 int arrarr[5][5]; // expected-error {{automatic variable qualified with an address space}}
__attribute__((address_space(-1))) int *_boundsA; // expected-error {{address space is negative}}
- __attribute__((address_space(0x7FFFFF))) int *_boundsB;
+ __attribute__((address_space(0x7FFFFF))) int *_boundsB; // expected-error {{address space is larger than the maximum supported}}
__attribute__((address_space(0x1000000))) int *_boundsC; // expected-error {{address space is larger than the maximum supported}}
// chosen specifically to overflow 32 bits and come out reasonable
__attribute__((address_space(4294967500))) int *_boundsD; // expected-error {{address space is larger than the maximum supported}}
diff --git a/test/Sema/alias-redefinition.c b/test/Sema/alias-redefinition.c
index 91f4b2714cd0..a4c06eebf499 100644
--- a/test/Sema/alias-redefinition.c
+++ b/test/Sema/alias-redefinition.c
@@ -19,9 +19,8 @@ void f4() {}
void fun4(void) __attribute((alias("f4")));
void fun4(void);
-// FIXME: We should produce a special case error for this.
void f5() {}
-void __attribute((alias("f5"))) fun5(void) {} // expected-error {{redefinition of 'fun5'}} // expected-note {{previous definition}}
+void __attribute((alias("f5"))) fun5(void) {} // expected-error {{definition 'fun5' cannot also be an alias}}
int var1 __attribute((alias("v1"))); // expected-error {{definition 'var1' cannot also be an alias}}
static int var2 __attribute((alias("v2"))) = 2; // expected-error {{definition 'var2' cannot also be an alias}}
diff --git a/test/Sema/alloc-align-attr.c b/test/Sema/alloc-align-attr.c
new file mode 100644
index 000000000000..bf8591625dab
--- /dev/null
+++ b/test/Sema/alloc-align-attr.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// return values
+void test_void_alloc_align(void) __attribute__((alloc_align(1))); // expected-warning {{'alloc_align' attribute only applies to return values that are pointers}}
+void *test_ptr_alloc_align(int a) __attribute__((alloc_align(1))); // no-warning
+
+int j __attribute__((alloc_align(1))); // expected-warning {{'alloc_align' attribute only applies to non-K&R-style functions}}
+void *test_no_params_zero(void) __attribute__((alloc_align(0))); // expected-error {{'alloc_align' attribute parameter 1 is out of bounds}}
+void *test_no_params(void) __attribute__((alloc_align(1))); // expected-error {{'alloc_align' attribute parameter 1 is out of bounds}}
+void *test_incorrect_param_type(float a) __attribute__((alloc_align(1))); // expected-error {{'alloc_align' attribute argument may only refer to a function parameter of integer type}}
+
+// argument type
+void *test_bad_param_type(void) __attribute((alloc_align(1.1))); // expected-error {{'alloc_align' attribute requires parameter 1 to be an integer constant}}
+
+// argument count
+void *test_no_fn_proto() __attribute__((alloc_align)); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto() __attribute__((alloc_align())); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto() __attribute__((alloc_align(32, 45, 37))); // expected-error {{'alloc_align' attribute takes one argument}}
+
diff --git a/test/Sema/altivec-init.c b/test/Sema/altivec-init.c
index 973aab15d466..1c20450a6d01 100644
--- a/test/Sema/altivec-init.c
+++ b/test/Sema/altivec-init.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=powerpc-apple-darwin8 -faltivec -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -triple=powerpc-apple-darwin8 -target-feature +altivec -verify -pedantic -fsyntax-only
typedef int v4 __attribute((vector_size(16)));
typedef short v8 __attribute((vector_size(16)));
@@ -23,8 +23,8 @@ v8 foo(void) {
return (v8){0, 1, 2, 3, 1, 2, 3, 4};
- // FIXME: test that (type)(fn)(args) still works with -faltivec
- // FIXME: test that c++ overloaded commas still work -faltivec
+ // FIXME: test that (type)(fn)(args) still works with -maltivec
+ // FIXME: test that c++ overloaded commas still work -maltivec
}
void __attribute__((__overloadable__)) f(v4 a)
diff --git a/test/Sema/arm-interrupt-attr.c b/test/Sema/arm-interrupt-attr.c
index b9684f0b46c1..3a6cdbe0e072 100644
--- a/test/Sema/arm-interrupt-attr.c
+++ b/test/Sema/arm-interrupt-attr.c
@@ -17,3 +17,19 @@ __attribute__((interrupt("UNDEF"))) void foo7() {}
__attribute__((interrupt)) void foo8() {}
__attribute__((interrupt())) void foo9() {}
__attribute__((interrupt(""))) void foo10() {}
+
+void callee1();
+__attribute__((interrupt("IRQ"))) void callee2();
+void caller1() {
+ callee1();
+ callee2();
+}
+__attribute__((interrupt("IRQ"))) void caller2() {
+ callee1(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers}}
+ callee2();
+}
+
+void (*callee3)();
+__attribute__((interrupt("IRQ"))) void caller3() {
+ callee3(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers}}
+}
diff --git a/test/Sema/ast-print.c b/test/Sema/ast-print.c
index 4c0aef5b2f3f..f701b1220953 100644
--- a/test/Sema/ast-print.c
+++ b/test/Sema/ast-print.c
@@ -65,3 +65,12 @@ void initializers() {
// CHECK: } z = {(struct Z){}};
} z = {(struct Z){}};
}
+
+// CHECK-LABEL: enum EnumWithAttributes {
+enum EnumWithAttributes {
+ // CHECK-NEXT: EnumWithAttributesFoo __attribute__((deprecated(""))),
+ EnumWithAttributesFoo __attribute__((deprecated)),
+ // CHECK-NEXT: EnumWithAttributesBar __attribute__((unavailable(""))) = 50
+ EnumWithAttributesBar __attribute__((unavailable)) = 50
+ // CHECK-NEXT: } __attribute__((deprecated("")))
+} __attribute__((deprecated));
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
index 8566a0e94362..89c06860fb4e 100644
--- a/test/Sema/attr-deprecated.c
+++ b/test/Sema/attr-deprecated.c
@@ -1,10 +1,12 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -std=c89 -verify -fsyntax-only
+// RUN: %clang_cc1 %s -std=c99 -verify -fsyntax-only
int f() __attribute__((deprecated)); // expected-note 2 {{'f' has been explicitly marked deprecated here}}
-void g() __attribute__((deprecated));
-void g(); // expected-note {{'g' has been explicitly marked deprecated here}}
+void g() __attribute__((deprecated));// expected-note {{'g' has been explicitly marked deprecated here}}
+void g();
-extern int var __attribute__((deprecated)); // expected-note {{'var' has been explicitly marked deprecated here}}
+extern int var __attribute__((deprecated)); // expected-note 2 {{'var' has been explicitly marked deprecated here}}
int a() {
int (*ptr)() = f; // expected-warning {{'f' is deprecated}}
@@ -17,13 +19,13 @@ int a() {
}
// test if attributes propagate to variables
-extern int var; // expected-note {{'var' has been explicitly marked deprecated here}}
+extern int var;
int w() {
return var; // expected-warning {{'var' is deprecated}}
}
-int old_fn() __attribute__ ((deprecated));
-int old_fn(); // expected-note {{'old_fn' has been explicitly marked deprecated here}}
+int old_fn() __attribute__ ((deprecated));// expected-note {{'old_fn' has been explicitly marked deprecated here}}
+int old_fn();
int (*fn_ptr)() = old_fn; // expected-warning {{'old_fn' is deprecated}}
int old_fn() {
@@ -44,8 +46,8 @@ void test1(struct foo *F) {
typedef struct foo foo_dep __attribute__((deprecated)); // expected-note 12 {{'foo_dep' has been explicitly marked deprecated here}}
foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}}
-struct __attribute__((deprecated,
- invalid_attribute)) bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}} expected-note 2 {{'bar_dep' has been explicitly marked deprecated here}}
+struct __attribute__((deprecated, // expected-note 2 {{'bar_dep' has been explicitly marked deprecated here}}
+ invalid_attribute)) bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}}
struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}}
@@ -121,11 +123,12 @@ struct test22 {
__attribute((deprecated)) foo_dep e, f;
};
-typedef int test23_ty __attribute((deprecated));
+typedef int test23_ty __attribute((deprecated));
// Redefining a typedef is a C11 feature.
#if __STDC_VERSION__ <= 199901L
// expected-note@-3 {{'test23_ty' has been explicitly marked deprecated here}}
#else
-typedef int test23_ty; // expected-note {{'test23_ty' has been explicitly marked deprecated here}}
+// expected-note@-5 {{'test23_ty' has been explicitly marked deprecated here}}
+typedef int test23_ty;
#endif
test23_ty test23_v; // expected-warning {{'test23_ty' is deprecated}}
diff --git a/test/Sema/attr-external-source-symbol.c b/test/Sema/attr-external-source-symbol.c
new file mode 100644
index 000000000000..af6e6bc79e7b
--- /dev/null
+++ b/test/Sema/attr-external-source-symbol.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+
+void threeClauses() __attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration)));
+
+void twoClauses() __attribute__((external_source_symbol(language="Swift", defined_in="module")));
+
+void fourClauses() __attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration, generated_declaration))); // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}}
+
+void oneClause() __attribute__((external_source_symbol(generated_declaration)));
+
+void noArguments()
+__attribute__((external_source_symbol)); // expected-error {{'external_source_symbol' attribute takes at least 1 argument}}
+
+void namedDeclsOnly() {
+ int (^block)(void) = ^ (void)
+ __attribute__((external_source_symbol(language="Swift"))) { // expected-warning {{'external_source_symbol' attribute only applies to named declarations}}
+ return 1;
+ };
+}
diff --git a/test/Sema/attr-ifunc.c b/test/Sema/attr-ifunc.c
index d177b7168488..8f9c22f84927 100644
--- a/test/Sema/attr-ifunc.c
+++ b/test/Sema/attr-ifunc.c
@@ -39,5 +39,9 @@ void f1() __attribute__((ifunc("f1_ifunc")));
//expected-error@-1 {{definition with same mangled name as another definition}}
void* f1_ifunc() { return 0; }
+void* f6_ifunc(int i);
+void __attribute__((ifunc("f6_ifunc"))) f6() {}
+//expected-error@-1 {{definition 'f6' cannot also be an ifunc}}
+
#endif
#endif
diff --git a/test/Sema/auto-type.c b/test/Sema/auto-type.c
index 9fadb90c2cda..ff7228785ac3 100644
--- a/test/Sema/auto-type.c
+++ b/test/Sema/auto-type.c
@@ -7,7 +7,7 @@ __auto_type b = 5.0;
__auto_type c = &b;
__auto_type d = (struct {int a;}) {5};
_Static_assert(__builtin_types_compatible_p(__typeof(a), int), "");
-__auto_type e = e; // expected-error {{variable 'e' declared with '__auto_type' type cannot appear in its own initializer}}
+__auto_type e = e; // expected-error {{variable 'e' declared with deduced type '__auto_type' cannot appear in its own initializer}}
struct s { __auto_type a; }; // expected-error {{'__auto_type' not allowed in struct member}}
diff --git a/test/Sema/avr-interrupt-attr.c b/test/Sema/avr-interrupt-attr.c
new file mode 100644
index 000000000000..2dfc72a354da
--- /dev/null
+++ b/test/Sema/avr-interrupt-attr.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -triple avr-unknown-unknown -verify -fsyntax-only
+struct a { int b; };
+
+struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions}}
+
+__attribute__((interrupt(12))) void foo(void) { } // expected-error {{'interrupt' attribute takes no arguments}}
+
+__attribute__((interrupt)) void food() {}
diff --git a/test/Sema/avr-signal-attr.c b/test/Sema/avr-signal-attr.c
new file mode 100644
index 000000000000..a5920bf4045c
--- /dev/null
+++ b/test/Sema/avr-signal-attr.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -triple avr-unknown-unknown -verify -fsyntax-only
+struct a { int b; };
+
+struct a test __attribute__((signal)); // expected-warning {{'signal' attribute only applies to functions}}
+
+__attribute__((signal(12))) void foo(void) { } // expected-error {{'signal' attribute takes no arguments}}
+
+__attribute__((signal)) void food() {}
diff --git a/test/Sema/builtins-ppc.c b/test/Sema/builtins-ppc.c
index 60872a614e4c..5c45d02b414c 100644
--- a/test/Sema/builtins-ppc.c
+++ b/test/Sema/builtins-ppc.c
@@ -1,9 +1,9 @@
// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -faltivec -target-feature +htm \
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +htm \
// RUN: -triple powerpc64-unknown-unknown -DTEST_HTM -fsyntax-only \
// RUN: -verify %s
-// RUN: %clang_cc1 -faltivec -target-feature +crypto \
+// RUN: %clang_cc1 -target-feature +altivec -target-feature +crypto \
// RUN: -triple powerpc64le-unknown-unknown -DTEST_CRYPTO -fsyntax-only \
// RUN: -verify %s
diff --git a/test/Sema/builtins-x86.c b/test/Sema/builtins-x86.c
index 6929dcc65090..074efe16ade6 100644
--- a/test/Sema/builtins-x86.c
+++ b/test/Sema/builtins-x86.c
@@ -4,6 +4,7 @@ typedef long long __m128i __attribute__((__vector_size__(16)));
typedef float __m128 __attribute__((__vector_size__(16)));
typedef double __m128d __attribute__((__vector_size__(16)));
+typedef long long __m512i __attribute__((__vector_size__(64)));
typedef float __m512 __attribute__((__vector_size__(64)));
typedef double __m512d __attribute__((__vector_size__(64)));
@@ -69,3 +70,16 @@ __m128i test__builtin_ia32_vpcomq(__m128i __a, __m128i __b) {
__mmask16 test__builtin_ia32_cmpps512_mask_rounding(__m512 __a, __m512 __b, __mmask16 __u) {
__builtin_ia32_cmpps512_mask(__a, __b, 0, __u, 0); // expected-error {{invalid rounding argument}}
}
+
+__m128i test_mm_mask_i32gather_epi32(__m128i a, int const *b, __m128i c, __m128i mask) {
+ return __builtin_ia32_gatherd_d(a, b, c, mask, 5); // expected-error {{scale argument must be 1, 2, 4, or 8}}
+}
+
+__m512i _mm512_mask_prefetch_i32gather_ps(__m512i index, __mmask16 mask, int const *addr) {
+ return __builtin_ia32_gatherpfdps(mask, index, addr, 5, 1); // expected-error {{scale argument must be 1, 2, 4, or 8}}
+}
+
+__m512 _mm512_mask_prefetch_i32gather_ps_2(__m512i index, __mmask16 mask, int const *addr) {
+ return __builtin_ia32_gatherpfdps(mask, index, addr, 1, 1); // expected-error {{argument should be a value from 2 to 3}}
+}
+
diff --git a/test/Sema/callingconv-cast.c b/test/Sema/callingconv-cast.c
index 12c0dcbc256a..599a7d1e66d7 100644
--- a/test/Sema/callingconv-cast.c
+++ b/test/Sema/callingconv-cast.c
@@ -15,6 +15,13 @@ void mismatched_before_winapi(int x) {}
// expected-note@+1 3 {{consider defining 'mismatched' with the 'stdcall' calling convention}}
void mismatched(int x) {}
+// expected-note@+1 {{consider defining 'mismatched_declaration' with the 'stdcall' calling convention}}
+void mismatched_declaration(int x);
+
+// expected-note@+1 {{consider defining 'suggest_fix_first_redecl' with the 'stdcall' calling convention}}
+void suggest_fix_first_redecl(int x);
+void suggest_fix_first_redecl(int x);
+
typedef void (WINAPI *callback_t)(int);
void take_callback(callback_t callback);
@@ -46,6 +53,12 @@ int main() {
// Another way to suppress the warning.
take_callback((callback_t)(void*)mismatched);
+ // Warn on declarations as well as definitions.
+ // expected-warning@+1 {{cast between incompatible calling conventions 'cdecl' and 'stdcall'}}
+ take_callback((callback_t)mismatched_declaration);
+ // expected-warning@+1 {{cast between incompatible calling conventions 'cdecl' and 'stdcall'}}
+ take_callback((callback_t)suggest_fix_first_redecl);
+
// Don't warn, because we're casting from stdcall to cdecl. Usually that means
// the programmer is rinsing the function pointer through some kind of opaque
// API.
diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c
index bfb58bc573e1..1b0a325dd188 100644
--- a/test/Sema/const-eval.c
+++ b/test/Sema/const-eval.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux %s -Wno-tautological-pointer-compare
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s -Wno-tautological-pointer-compare
#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
int x;
@@ -126,7 +126,7 @@ EVAL_EXPR(48, &x != &x - 1 ? 1 : -1)
EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // expected-error {{must have a constant size}}
extern struct Test50S Test50;
-EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned)&Test50 + 10)) // expected-error {{must have a constant size}}
+EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned long)&Test50 + 10)) // expected-error {{must have a constant size}}
// <rdar://problem/11874571>
EVAL_EXPR(51, 0 != (float)1e99)
@@ -137,3 +137,10 @@ void PR21945() { int i = (({}), 0l); }
void PR24622();
struct PR24622 {} pr24622;
EVAL_EXPR(52, &pr24622 == (void *)&PR24622); // expected-error {{must have a constant size}}
+
+// We evaluate these by providing 2s' complement semantics in constant
+// expressions, like we do for integers.
+void *PR28739a = (__int128)(unsigned long)-1 + &PR28739a;
+void *PR28739b = &PR28739b + (__int128)(unsigned long)-1;
+__int128 PR28739c = (&PR28739c + (__int128)(unsigned long)-1) - &PR28739c;
+void *PR28739d = &(&PR28739d)[(__int128)(unsigned long)-1];
diff --git a/test/Sema/declspec-naked.c b/test/Sema/declspec-naked.c
new file mode 100644
index 000000000000..ad40941a5f00
--- /dev/null
+++ b/test/Sema/declspec-naked.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fsyntax-only -fdeclspec -verify %s
+// RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -fsyntax-only -fdeclspec -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fsyntax-only -fdeclspec -verify %s
+#if defined(_M_IX86) || defined(_M_ARM)
+// CHECK: expected-no-diagnostics
+#endif
+
+void __declspec(naked) f(void) {}
+#if !defined(_M_IX86) && !defined(_M_ARM)
+// expected-error@-2{{'naked' attribute is not supported on 'x86_64'}}
+#endif
diff --git a/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c
index a4582deb171e..43f3318824d5 100644
--- a/test/Sema/designated-initializers.c
+++ b/test/Sema/designated-initializers.c
@@ -351,3 +351,20 @@ overwrite_string4[] = {
{ { 'f', 'o', 'o' }, 1 },
[0].L[4] = 'x' // no-warning
};
+
+struct {
+ struct { } s1;
+ union {
+ int a;
+ int b;
+ } u1;
+} s = {
+ .s1 = {
+ .x = 0, // expected-error{{field designator}}
+ },
+
+ .u1 = {
+ .a = 0,
+ .b = 0,
+ },
+};
diff --git a/test/Sema/enable_if.c b/test/Sema/enable_if.c
index a11f53eb4930..9125bfaf0f14 100644
--- a/test/Sema/enable_if.c
+++ b/test/Sema/enable_if.c
@@ -139,8 +139,8 @@ void test7() {
void f4(int m) __attribute__((enable_if(0, "")));
void test8() {
- void (*p1)(int) = &f4; // expected-error{{cannot take address of function 'f4' becuase it has one or more non-tautological enable_if conditions}}
- void (*p2)(int) = f4; // expected-error{{cannot take address of function 'f4' becuase it has one or more non-tautological enable_if conditions}}
+ void (*p1)(int) = &f4; // expected-error{{cannot take address of function 'f4' because it has one or more non-tautological enable_if conditions}}
+ void (*p2)(int) = f4; // expected-error{{cannot take address of function 'f4' because it has one or more non-tautological enable_if conditions}}
}
void regular_enable_if(int a) __attribute__((enable_if(a, ""))); // expected-note 3{{declared here}}
diff --git a/test/Sema/enum-attr.c b/test/Sema/enum-attr.c
new file mode 100644
index 000000000000..933d8ccdcd89
--- /dev/null
+++ b/test/Sema/enum-attr.c
@@ -0,0 +1,130 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wassign-enum -Wswitch-enum -Wcovered-switch-default %s
+
+enum Enum {
+ A0 = 1, A1 = 10
+};
+
+enum __attribute__((enum_extensibility(closed))) EnumClosed {
+ B0 = 1, B1 = 10
+};
+
+enum __attribute__((enum_extensibility(open))) EnumOpen {
+ C0 = 1, C1 = 10
+};
+
+enum __attribute__((flag_enum)) EnumFlag {
+ D0 = 1, D1 = 8
+};
+
+enum __attribute__((flag_enum,enum_extensibility(closed))) EnumFlagClosed {
+ E0 = 1, E1 = 8
+};
+
+enum __attribute__((flag_enum,enum_extensibility(open))) EnumFlagOpen {
+ F0 = 1, F1 = 8
+};
+
+enum __attribute__((enum_extensibility(arg1))) EnumInvalidArg { // expected-warning{{'enum_extensibility' attribute argument not supported: 'arg1'}}
+ X0
+};
+
+// FIXME: The warning should mention that enum_extensibility takes only one argument.
+enum __attribute__((enum_extensibility(closed,open))) EnumTooManyArgs { // expected-error{{use of undeclared identifier 'open'}}
+ X1
+};
+
+enum __attribute__((enum_extensibility())) EnumTooFewArgs { // expected-error{{'enum_extensibility' attribute takes one argument}}
+ X2
+};
+
+struct __attribute__((enum_extensibility(open))) S { // expected-warning{{'enum_extensibility' attribute only applies to enums}}{
+};
+
+void test() {
+ enum Enum t0 = 100; // expected-warning{{integer constant not in range of enumerated type}}
+ t0 = 1;
+
+ switch (t0) { // expected-warning{{enumeration value 'A1' not handled in switch}}
+ case A0: break;
+ case 16: break; // expected-warning{{case value not in enumerated type}}
+ }
+
+ switch (t0) {
+ case A0: break;
+ case A1: break;
+ default: break; // expected-warning{{default label in switch which covers all enumeration}}
+ }
+
+ enum EnumClosed t1 = 100; // expected-warning{{integer constant not in range of enumerated type}}
+ t1 = 1;
+
+ switch (t1) { // expected-warning{{enumeration value 'B1' not handled in switch}}
+ case B0: break;
+ case 16: break; // expected-warning{{case value not in enumerated type}}
+ }
+
+ switch (t1) {
+ case B0: break;
+ case B1: break;
+ default: break; // expected-warning{{default label in switch which covers all enumeration}}
+ }
+
+ enum EnumOpen t2 = 100;
+ t2 = 1;
+
+ switch (t2) { // expected-warning{{enumeration value 'C1' not handled in switch}}
+ case C0: break;
+ case 16: break;
+ }
+
+ switch (t2) {
+ case C0: break;
+ case C1: break;
+ default: break;
+ }
+
+ enum EnumFlag t3 = 5; // expected-warning{{integer constant not in range of enumerated type}}
+ t3 = 9;
+
+ switch (t3) { // expected-warning{{enumeration value 'D1' not handled in switch}}
+ case D0: break;
+ case 9: break;
+ case 16: break; // expected-warning{{case value not in enumerated type}}
+ }
+
+ switch (t3) {
+ case D0: break;
+ case D1: break;
+ default: break;
+ }
+
+ enum EnumFlagClosed t4 = 5; // expected-warning{{integer constant not in range of enumerated type}}
+ t4 = 9;
+
+ switch (t4) { // expected-warning{{enumeration value 'E1' not handled in switch}}
+ case E0: break;
+ case 9: break;
+ case 16: break; // expected-warning{{case value not in enumerated type}}
+ }
+
+ switch (t4) {
+ case E0: break;
+ case E1: break;
+ default: break;
+ }
+
+ enum EnumFlagOpen t5 = 5;
+ t5 = 9;
+
+ switch (t5) { // expected-warning{{enumeration value 'F1' not handled in switch}}
+ case F0: break;
+ case 9: break;
+ case 16: break;
+ }
+
+ switch (t5) {
+ case F0: break;
+ case F1: break;
+ default: break;
+ }
+}
diff --git a/test/Sema/expr-address-of.c b/test/Sema/expr-address-of.c
index 32bd0dfdd5b0..480871afad2a 100644
--- a/test/Sema/expr-address-of.c
+++ b/test/Sema/expr-address-of.c
@@ -102,8 +102,9 @@ char* f7() {
register struct {char* x;} t1 = {"Hello"};
char* dummy1 = &(t1.x[0]);
- struct {int a : 10;} t2;
+ struct {int a : 10; struct{int b : 10;};} t2;
int* dummy2 = &(t2.a); // expected-error {{address of bit-field requested}}
+ int* dummy3 = &(t2.b); // expected-error {{address of bit-field requested}}
void* t3 = &(*(void*)0);
}
diff --git a/test/Sema/knr-def-call.c b/test/Sema/knr-def-call.c
index 80ad0d820b1a..2bd4a79fd0f8 100644
--- a/test/Sema/knr-def-call.c
+++ b/test/Sema/knr-def-call.c
@@ -1,13 +1,13 @@
-// RUN: %clang_cc1 -Wconversion -Wliteral-conversion -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -Wconversion -Wliteral-conversion -fsyntax-only -verify %s
// C DR #316, PR 3626.
void f0(a, b, c, d) int a,b,c,d; {}
-void t0(void) {
+void t0(void) {
f0(1); // expected-warning{{too few arguments}}
}
void f1(a, b) int a, b; {}
-void t1(void) {
+void t1(void) {
f1(1, 2, 3); // expected-warning{{too many arguments}}
}
@@ -30,7 +30,7 @@ char *rindex(s, c)
// PR8314
void proto(int);
-void proto(x)
+void proto(x)
int x;
{
}
@@ -39,3 +39,9 @@ void use_proto() {
proto(42.1); // expected-warning{{implicit conversion from 'double' to 'int' changes value from 42.1 to 42}}
(&proto)(42.1); // expected-warning{{implicit conversion from 'double' to 'int' changes value from 42.1 to 42}}
}
+
+// PR31020
+void func(short d) __attribute__((cdecl)); // expected-note{{previous declaration is here}}
+void __attribute__((cdecl)) func(d)
+ short d; // expected-warning{{promoted type 'int' of K&R function parameter is not compatible with the parameter type 'short' declared in a previous prototype}}
+{}
diff --git a/test/Sema/ms-inline-asm.c b/test/Sema/ms-inline-asm.c
index abf10b67cce1..952112ea8cf8 100644
--- a/test/Sema/ms-inline-asm.c
+++ b/test/Sema/ms-inline-asm.c
@@ -1,5 +1,5 @@
// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fms-extensions -fasm-blocks -Wno-microsoft -Wunused-label -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -fms-extensions -fasm-blocks -Wno-microsoft -Wunused-label -verify -fsyntax-only
void t1(void) {
__asm __asm // expected-error {{__asm used with no assembly instructions}}
diff --git a/test/Sema/nonnull.c b/test/Sema/nonnull.c
index e98a8194dbeb..217bbb16df60 100644
--- a/test/Sema/nonnull.c
+++ b/test/Sema/nonnull.c
@@ -167,3 +167,10 @@ void returns_nonnull_warning_tests() {
int and_again = !returns_nonnull_whee(); // expected-warning {{nonnull function call 'returns_nonnull_whee()' will evaluate to 'true' on first encounter}}
and_again = !returns_nonnull_whee(); // expected-warning {{nonnull function call 'returns_nonnull_whee()' will evaluate to 'true' on first encounter}}
}
+
+void pr30828(char *p __attribute__((nonnull)));
+void pr30828(char *p) {}
+
+void call_pr30828() {
+ pr30828(0); // expected-warning {{null passed to a callee that requires a non-null argument}}
+}
diff --git a/test/Sema/pr30306.cpp b/test/Sema/pr30306.cpp
new file mode 100644
index 000000000000..413e2f5ab559
--- /dev/null
+++ b/test/Sema/pr30306.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux-gnu -emit-llvm < %s | FileCheck %s
+
+struct A { A(int); ~A(); };
+int f(const A &);
+// CHECK: call void @_ZN1AC1Ei
+// CHECK-NEXT: call i32 @_Z1fRK1A
+// CHECK-NEXT: call void @_ZN1AD1Ev
+// CHECK: call void @_ZN1AC1Ei
+// CHECK-NEXT: call i32 @_Z1fRK1A
+// CHECK-NEXT: call void @_ZN1AD1Ev
+template<typename T> void g() {
+ int a[f(3)];
+ int b[f(3)];
+}
+int main() { g<int>(); }
diff --git a/test/Sema/transparent-union.c b/test/Sema/transparent-union.c
index a1a67dfd26fc..dfbadcfe62c7 100644
--- a/test/Sema/transparent-union.c
+++ b/test/Sema/transparent-union.c
@@ -54,11 +54,21 @@ typedef union {
aligned_struct8 s8; // expected-warning{{alignment of field}}
} TU1 __attribute__((transparent_union));
+typedef union __attribute__((transparent_union)) {
+ aligned_struct4 s4; // expected-note{{alignment of first field}}
+ aligned_struct8 s8; // expected-warning{{alignment of field}}
+} TU1b ;
+
typedef union {
char c; // expected-note{{size of first field is 8 bits}}
int i; // expected-warning{{size of field}}
} TU2 __attribute__((transparent_union));
+typedef union __attribute__((transparent_union)){
+ char c; // expected-note{{size of first field is 8 bits}}
+ int i; // expected-warning{{size of field}}
+} TU2b;
+
typedef union {
float f; // expected-warning{{floating}}
} TU3 __attribute__((transparent_union));
@@ -98,3 +108,17 @@ union pr30520a { int b[]; } __attribute__((transparent_union)); // expected-erro
union pr30520s { struct stb b; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'struct stb'}}
union pr30520s2 { int *v; struct stb b; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'struct stb'}}
+
+typedef union __attribute__((__transparent_union__)) {
+ int *i;
+ struct st *s;
+} TU6;
+
+void bar(TU6);
+
+void foo11(int *i) {
+ bar(i);
+}
+void foo2(struct st *s) {
+ bar(s);
+}
diff --git a/test/Sema/unaligned-qualifier.c b/test/Sema/unaligned-qualifier.c
new file mode 100644
index 000000000000..3a66c4ffbb3b
--- /dev/null
+++ b/test/Sema/unaligned-qualifier.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -fms-extensions
+
+int __unaligned * p1; // expected-note {{previous definition is here}}
+int * p1; // expected-error {{redefinition of 'p1' with a different type: 'int *' vs '__unaligned int *'}}
diff --git a/test/Sema/vector-ops.c b/test/Sema/vector-ops.c
index f2953417f545..9cdd9d2f1748 100644
--- a/test/Sema/vector-ops.c
+++ b/test/Sema/vector-ops.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion -triple x86_64-apple-darwin10
typedef unsigned int v2u __attribute__ ((vector_size (8)));
typedef int v2s __attribute__ ((vector_size (8)));
typedef float v2f __attribute__ ((vector_size(8)));
@@ -13,9 +13,9 @@ void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
(void)(~v2fa); // expected-error{{invalid argument type 'v2f' (vector of 2 'float' values) to unary}}
// Comparison operators
- v2ua = (v2ua==v2sa); // expected-warning{{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from 'int __attribute__((ext_vector_type(2)))' (vector of 2 'int' values)}}
+ v2ua = (v2ua==v2sa); // expected-warning{{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
v2sa = (v2ua==v2sa);
-
+
// Arrays
int array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u' (vector of 2 'unsigned int' values)}}
int array2[17];
@@ -26,4 +26,110 @@ void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
v2s *v2s_ptr;
v2s_ptr = v2u_ptr; // expected-warning{{converts between pointers to integer types with different sign}}
}
-
+
+void testLogicalVecVec(v2u v2ua, v2s v2sa, v2f v2fa) {
+
+ // Logical operators
+ v2ua = v2ua && v2ua; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2ua = v2ua || v2ua; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2ua = v2sa && v2ua; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2ua = v2sa || v2ua; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2ua = v2ua && v2fa; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2ua = v2ua || v2fa; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2ua = v2sa && v2fa; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2ua = v2sa || v2fa; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2sa = v2sa && v2sa;
+ v2sa = v2sa || v2sa;
+
+ v2sa = v2ua && v2ua;
+ v2sa = v2ua || v2ua;
+
+ v2sa = v2sa && v2ua;
+ v2sa = v2sa || v2ua;
+
+ v2sa = v2sa && v2fa;
+ v2sa = v2sa || v2fa;
+
+ v2sa = v2ua && v2fa;
+ v2sa = v2ua || v2fa;
+
+ v2fa = v2fa && v2fa; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2fa = v2fa || v2fa; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2fa = v2sa && v2fa; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2fa = v2sa || v2fa; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2fa = v2ua && v2fa; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2fa = v2ua || v2fa; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2fa = v2ua && v2ua; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2fa = v2ua || v2ua; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2fa = v2sa && v2sa; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2fa = v2sa || v2sa; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+
+ v2fa = v2sa && v2ua; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+ v2fa = v2sa || v2ua; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+}
+
+void testLogicalVecScalar(v2u v2ua, v2s v2sa, v2f v2fa) {
+
+ unsigned u1;
+ v2ua = v2ua && u1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'unsigned int')}}
+ v2ua = v2ua || u1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'unsigned int')}}
+
+ v2sa = v2sa && u1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'unsigned int')}}
+ v2sa = v2sa || u1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'unsigned int')}}
+
+ v2ua = v2sa && u1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'unsigned int')}}
+ v2ua = v2sa || u1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'unsigned int')}}
+ v2sa = v2ua && u1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'unsigned int')}}
+ v2sa = v2ua || u1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'unsigned int')}}
+
+ v2ua = v2fa && u1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'unsigned int')}}
+ v2ua = v2fa || u1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'unsigned int')}}
+
+ v2sa = v2fa && u1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'unsigned int')}}
+ v2sa = v2fa || u1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'unsigned int')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'unsigned int')}}
+
+ int s1;
+ v2ua = v2ua && s1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'int')}}
+ v2ua = v2ua || s1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'int')}}
+
+ v2sa = v2sa && s1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'int')}}
+ v2sa = v2sa || s1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'int')}}
+
+ v2ua = v2sa && s1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'int')}}
+ v2ua = v2sa || s1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'int')}}
+ v2sa = v2ua && s1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'int')}}
+ v2sa = v2ua || s1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'int')}}
+
+ v2ua = v2fa && s1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'int')}}
+ v2ua = v2fa || s1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'int')}}
+
+ v2sa = v2fa && s1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'int')}}
+ v2sa = v2fa || s1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'int')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'int')}}
+
+ float f1;
+ v2ua = v2ua && f1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'float')}}
+ v2ua = v2ua || f1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'float')}}
+
+ v2sa = v2sa && f1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'float')}}
+ v2sa = v2sa || f1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'float')}}
+
+ v2ua = v2sa && f1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'float')}}
+ v2ua = v2sa || f1; // expected-error {{cannot convert between vector values of different size ('v2s' (vector of 2 'int' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'float')}}
+ v2sa = v2ua && f1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'float')}}
+ v2sa = v2ua || f1; // expected-error {{cannot convert between vector values of different size ('v2u' (vector of 2 'unsigned int' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2u' (vector of 2 'unsigned int' values) and 'float')}}
+
+ v2ua = v2fa && f1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'float')}}
+ v2ua = v2fa || f1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'float')}}
+
+ v2sa = v2fa && f1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'float')}}
+ v2sa = v2fa || f1; // expected-error {{cannot convert between vector values of different size ('v2f' (vector of 2 'float' values) and 'float')}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'float')}}
+
+}
diff --git a/test/Sema/warn-strict-prototypes.c b/test/Sema/warn-strict-prototypes.c
index 496579c1f60e..a28f57d48c84 100644
--- a/test/Sema/warn-strict-prototypes.c
+++ b/test/Sema/warn-strict-prototypes.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -Wstrict-prototypes -verify %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -Wstrict-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// function declaration with unspecified params
void foo1(); // expected-warning {{this function declaration is not a prototype}}
@@ -60,3 +60,8 @@ void foo10(p, p2) void *p; {} // expected-warning {{old-style function definitio
// K&R function definition with previous prototype declared is not diagnosed.
void foo11(int p, int p2);
void foo11(p, p2) int p; int p2; {}
+
+// PR31020
+void __attribute__((cdecl)) foo12(d) // expected-warning {{this old-style function definition is not preceded by a prototype}}
+ short d;
+{}
diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c
index 34e0296a2049..440aa0a5a174 100644
--- a/test/Sema/warn-unreachable.c
+++ b/test/Sema/warn-unreachable.c
@@ -451,3 +451,50 @@ void unaryOpFixitCastSubExpr(int x) {
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:")"
unaryOpFixitCastSubExpr(x); // expected-warning {{code will never be executed}}
}
+
+#define false 0
+#define true 1
+
+void testTrueFalseMacros() {
+ if (false) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
+ testTrueFalseMacros(); // expected-warning {{code will never be executed}}
+ if (!true) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
+ testTrueFalseMacros(); // expected-warning {{code will never be executed}}
+}
+
+int pr13910_foo(int x) {
+ if (x == 1)
+ return 0;
+ else
+ return x;
+ __builtin_unreachable(); // expected no warning
+}
+
+int pr13910_bar(int x) {
+ switch (x) {
+ default:
+ return x + 1;
+ }
+ pr13910_foo(x); // expected-warning {{code will never be executed}}
+}
+
+int pr13910_bar2(int x) {
+ if (x == 1)
+ return 0;
+ else
+ return x;
+ pr13910_foo(x); // expected-warning {{code will never be executed}}
+ __builtin_unreachable(); // expected no warning
+ pr13910_foo(x); // expected-warning {{code will never be executed}}
+}
+
+void pr13910_noreturn() {
+ raze();
+ __builtin_unreachable(); // expected no warning
+}
+
+void pr13910_assert() {
+ myassert(0 && "unreachable");
+ return;
+ __builtin_unreachable(); // expected no warning
+}
diff --git a/test/Sema/xray-log-args-oob.c b/test/Sema/xray-log-args-oob.c
new file mode 100644
index 000000000000..a6be0f81cb47
--- /dev/null
+++ b/test/Sema/xray-log-args-oob.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c11
+void foo(int) __attribute__((xray_log_args(1)));
+struct __attribute__((xray_log_args(1))) a { int x; }; // expected-warning {{'xray_log_args' attribute only applies to functions and methods}}
+
+void fop() __attribute__((xray_log_args(1))); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
+
+void foq() __attribute__((xray_log_args(-1))); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
+
+void fos() __attribute__((xray_log_args(0))); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
diff --git a/test/Sema/xray-log-args-oob.cpp b/test/Sema/xray-log-args-oob.cpp
new file mode 100644
index 000000000000..414bce0c334a
--- /dev/null
+++ b/test/Sema/xray-log-args-oob.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c++11 -x c++
+void foo [[clang::xray_log_args(1)]] (int);
+struct [[clang::xray_log_args(1)]] a { int x; }; // expected-warning {{'xray_log_args' attribute only applies to functions and methods}}
+
+void fop [[clang::xray_log_args(1)]] (); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
+
+void foq [[clang::xray_log_args(-1)]] (); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
+
+void fos [[clang::xray_log_args(0)]] (); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
diff --git a/test/SemaCXX/Inputs/std-coroutine.h b/test/SemaCXX/Inputs/std-coroutine.h
new file mode 100644
index 000000000000..7a424f1e99cf
--- /dev/null
+++ b/test/SemaCXX/Inputs/std-coroutine.h
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify -fblocks -Wno-unreachable-code -Wno-unused-value
+#ifndef STD_COROUTINE_H
+#define STD_COROUTINE_H
+
+namespace std {
+namespace experimental {
+
+template <class Ret, typename... T>
+struct coroutine_traits { using promise_type = typename Ret::promise_type; };
+
+template <class Promise = void>
+struct coroutine_handle {
+ static coroutine_handle from_address(void *);
+};
+template <>
+struct coroutine_handle<void> {
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>);
+ static coroutine_handle from_address(void *);
+};
+
+struct suspend_always {
+ bool await_ready() { return false; }
+ void await_suspend(coroutine_handle<>) {}
+ void await_resume() {}
+};
+
+struct suspend_never {
+ bool await_ready() { return true; }
+ void await_suspend(coroutine_handle<>) {}
+ void await_resume() {}
+};
+
+} // namespace experimental
+} // namespace std
+
+#endif // STD_COROUTINE_H
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index e12dea1fb620..96088a084558 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions -DTEST1
+// RUN: %clang_cc1 -std=c++98 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions -DTEST1
+// RUN: %clang_cc1 -std=c++11 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions -DTEST1
// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fexceptions -fcxx-exceptions -DTEST2
#if TEST1
@@ -23,11 +25,17 @@ struct Derived : Base {
};
class A {
- virtual ~A() throw(); // expected-note {{overridden virtual function is here}}
+ virtual ~A() throw();
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{overridden virtual function is here}}
+#endif
};
class B : public A {
- virtual ~B(); // expected-warning {{exception specification of overriding function is more lax than base version}}
+ virtual ~B();
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{exception specification of overriding function is more lax than base version}}
+#endif
};
}
@@ -174,11 +182,18 @@ const int seventeen = 17;
typedef int Int;
struct X0 {
- enum E1 : Int { SomeOtherValue } field; // expected-warning{{enumeration types with a fixed underlying type are a C++11 extension}}
+ enum E1 : Int { SomeOtherValue } field;
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{enumeration types with a fixed underlying type are a C++11 extension}}
+#endif
+
enum E1 : seventeen;
};
-enum : long long { // expected-warning{{enumeration types with a fixed underlying type are a C++11 extension}}
+#if __cplusplus <= 199711L
+// expected-warning@+2 {{enumeration types with a fixed underlying type are a C++11 extension}}
+#endif
+enum : long long {
SomeValue = 0x100000000
};
@@ -450,7 +465,9 @@ struct SealedType sealed : SomeBase {
// FIXME. warning can be suppressed if we're also issuing error for overriding a 'final' function.
virtual void SealedFunction(); // expected-warning {{'SealedFunction' overrides a member function but is not marked 'override'}}
- // expected-warning@+1 {{'override' keyword is a C++11 extension}}
+#if __cplusplus <= 199711L
+ // expected-warning@+2 {{'override' keyword is a C++11 extension}}
+#endif
virtual void OverrideMe() override;
};
diff --git a/test/SemaCXX/P30636.cpp b/test/SemaCXX/P30636.cpp
new file mode 100644
index 000000000000..2e2affb0cfde
--- /dev/null
+++ b/test/SemaCXX/P30636.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wimplicit-fallthrough %s
+// expected-no-diagnostics
+
+template<bool param>
+int fallthrough_template(int i)
+{
+ switch (i) {
+ case 1:
+ if (param)
+ return 3;
+ [[clang::fallthrough]]; // no warning here, for an unreachable annotation (in the fallthrough_template<true> case) in a template function
+ case 2:
+ return 4;
+ default:
+ return 5;
+ }
+}
+
+template int fallthrough_template<true>(int);
+
diff --git a/test/SemaCXX/PR9572.cpp b/test/SemaCXX/PR9572.cpp
index d6dc2e06062c..79d3327ac86c 100644
--- a/test/SemaCXX/PR9572.cpp
+++ b/test/SemaCXX/PR9572.cpp
@@ -1,15 +1,50 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
class Base {
- virtual ~Base(); // expected-note {{implicitly declared private here}}
+ virtual ~Base();
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{implicitly declared private here}}
+#else
+ // expected-note@-4 {{overridden virtual function is here}}
+#endif
};
-struct Foo : public Base { // expected-error {{base class 'Base' has private destructor}}
- const int kBlah = 3; // expected-warning {{is a C++11 extension}}
+
+struct Foo : public Base {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{base class 'Base' has private destructor}}
+#else
+// expected-error@-4 {{deleted function '~Foo' cannot override a non-deleted function}}
+// expected-note@-5 {{overridden virtual function is here}}
+// expected-note@-6 3 {{destructor of 'Foo' is implicitly deleted because base class 'Base' has an inaccessible destructor}}
+#endif
+
+ const int kBlah = 3;
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{in-class initialization of non-static data member is a C++11 extension}}
+#endif
+
Foo();
};
+
struct Bar : public Foo {
- Bar() { } // expected-note {{implicit destructor for 'Foo' first required here}}
+#if __cplusplus >= 201103L
+// expected-error@-2 {{non-deleted function '~Bar' cannot override a deleted function}}
+// expected-note@-3 {{while declaring the implicit destructor for 'Bar'}}
+#endif
+ Bar() { }
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{implicit destructor for 'Foo' first required here}}
+#else
+ // expected-error@-4 {{attempt to use a deleted function}}
+#endif
};
+
struct Baz {
Foo f;
Baz() { }
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{attempt to use a deleted function}}
+#endif
};
diff --git a/test/SemaCXX/alloc-align-attr.cpp b/test/SemaCXX/alloc-align-attr.cpp
new file mode 100644
index 000000000000..74cfb7d7e486
--- /dev/null
+++ b/test/SemaCXX/alloc-align-attr.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct param_num {
+ void* Foo(int a) __attribute__((alloc_align(1))); // expected-error {{'alloc_align' attribute is invalid for the implicit this argument}}
+};
+
+
+template <typename T>
+struct dependent_ret {
+ T* Foo(int a) __attribute__((alloc_align(2)));// no-warning, ends up being int**.
+ T Foo2(int a) __attribute__((alloc_align(2)));// expected-warning {{'alloc_align' attribute only applies to return values that are pointers or references}}
+};
+
+// Following 2 errors associated only with the 'float' versions below.
+template <typename T>
+struct dependent_param_struct {
+ void* Foo(T param) __attribute__((alloc_align(2))); // expected-error {{'alloc_align' attribute argument may only refer to a function parameter of integer type}}
+};
+
+template <typename T>
+void* dependent_param_func(T param) __attribute__((alloc_align(1)));// expected-error {{'alloc_align' attribute argument may only refer to a function parameter of integer type}}
+
+template <int T>
+void* illegal_align_param(int p) __attribute__((alloc_align(T))); // expected-error {{'alloc_align' attribute requires parameter 1 to be an integer constant}}
+
+void dependent_impl() {
+ dependent_ret<int> a; // expected-note {{in instantiation of template class 'dependent_ret<int>' requested here}}
+ a.Foo(1);
+ a.Foo2(1);
+ dependent_ret<int*> b;
+ a.Foo(1);
+ a.Foo2(1);
+
+ dependent_param_struct<int> c;
+ c.Foo(1);
+ dependent_param_struct<float> d; // expected-note {{in instantiation of template class 'dependent_param_struct<float>' requested here}}
+ d.Foo(1.0);
+ dependent_param_func<int>(1);
+ dependent_param_func<float>(1); // expected-note {{in instantiation of function template specialization 'dependent_param_func<float>' requested here}}
+}
diff --git a/test/SemaCXX/altivec.cpp b/test/SemaCXX/altivec.cpp
index 351746617757..92f02838adf7 100644
--- a/test/SemaCXX/altivec.cpp
+++ b/test/SemaCXX/altivec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -faltivec -fno-lax-vector-conversions -triple powerpc-unknown-unknown -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -target-feature +altivec -fno-lax-vector-conversions -triple powerpc-unknown-unknown -fcxx-exceptions -verify %s
typedef int V4i __attribute__((vector_size(16)));
diff --git a/test/SemaCXX/anonymous-struct.cpp b/test/SemaCXX/anonymous-struct.cpp
index b584f89ff447..bb7e6eb92da3 100644
--- a/test/SemaCXX/anonymous-struct.cpp
+++ b/test/SemaCXX/anonymous-struct.cpp
@@ -21,6 +21,9 @@ struct E {
};
static struct {
};
+ class {
+ int anon_priv_field; // expected-error {{anonymous struct cannot contain a private data member}}
+ };
};
template <class T> void foo(T);
diff --git a/test/SemaCXX/array-bounds.cpp b/test/SemaCXX/array-bounds.cpp
index 80b3ee428944..8ae92e761301 100644
--- a/test/SemaCXX/array-bounds.cpp
+++ b/test/SemaCXX/array-bounds.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
int foo() {
int x[2]; // expected-note 4 {{array 'x' declared here}}
@@ -253,3 +253,19 @@ void test_rdar10916006(void)
int a[128]; // expected-note {{array 'a' declared here}}
a[(unsigned char)'\xA1'] = 1; // expected-warning {{array index 161 is past the end of the array}}
}
+
+struct P {
+ int a;
+ int b;
+};
+
+void test_struct_array_index() {
+ struct P p[10]; // expected-note {{array 'p' declared here}}
+ p[11] = {0, 1}; // expected-warning {{array index 11 is past the end of the array (which contains 10 elements)}}
+}
+
+int operator+(const struct P &s1, const struct P &s2);
+int test_operator_overload_struct_array_index() {
+ struct P x[10] = {0}; // expected-note {{array 'x' declared here}}
+ return x[1] + x[11]; // expected-warning {{array index 11 is past the end of the array (which contains 10 elements)}}
+}
diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp
index eab5a1c0ec08..1680c5c6760d 100644
--- a/test/SemaCXX/attr-deprecated.cpp
+++ b/test/SemaCXX/attr-deprecated.cpp
@@ -56,14 +56,14 @@ void f(B* b, C *c) {
}
struct D {
- virtual void f() __attribute__((deprecated));
- virtual void f(int) __attribute__((deprecated));
- virtual void f(int, int) __attribute__((deprecated));
+ virtual void f() __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}}
+ virtual void f(int) __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}}
+ virtual void f(int, int) __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}}
};
-void D::f() { } // expected-note{{'f' has been explicitly marked deprecated here}}
-void D::f(int v) { } // expected-note{{'f' has been explicitly marked deprecated here}}
-void D::f(int v1, int v2) { } // expected-note{{'f' has been explicitly marked deprecated here}}
+void D::f() { }
+void D::f(int v) { }
+void D::f(int v1, int v2) { }
void f(D* d) {
d->f(); // expected-warning{{'f' is deprecated}}
diff --git a/test/SemaCXX/attr-flag-enum-reject.cpp b/test/SemaCXX/attr-flag-enum-reject.cpp
deleted file mode 100644
index f28d60c0c295..000000000000
--- a/test/SemaCXX/attr-flag-enum-reject.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -Wassign-enum %s
-
-enum __attribute__((flag_enum)) flag { // expected-warning {{ignored}}
-};
diff --git a/test/SemaCXX/attr-noreturn.cpp b/test/SemaCXX/attr-noreturn.cpp
index 6edc86c43a7d..24598e132113 100644
--- a/test/SemaCXX/attr-noreturn.cpp
+++ b/test/SemaCXX/attr-noreturn.cpp
@@ -265,13 +265,13 @@ namespace PR15291 {
typedef void (*fptr_t)(int);
typedef void __attribute__((noreturn)) (*fptr_noreturn_t)(int);
- // expected-note@+1 {{candidate function not viable: no overload of 'bar' matching 'fptr_t' (aka 'void (*)(int)') for 1st argument}}
+ // expected-note@+1 {{candidate function not viable: no overload of 'bar' matching 'PR15291::fptr_t' (aka 'void (*)(int)') for 1st argument}}
void accept_fptr_t(fptr_t f) {
f(42);
}
- // expected-note@+2 {{candidate function not viable: no overload of 'baz' matching 'fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
- // expected-note@+1 {{candidate function not viable: no overload of 'qux' matching 'fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
+ // expected-note@+2 {{candidate function not viable: no overload of 'baz' matching 'PR15291::fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
+ // expected-note@+1 {{candidate function not viable: no overload of 'qux' matching 'PR15291::fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
void accept_fptr_noreturn_t(fptr_noreturn_t f) {
f(42);
}
diff --git a/test/SemaCXX/attr-require-constant-initialization.cpp b/test/SemaCXX/attr-require-constant-initialization.cpp
index 73f81cb1fc1d..3ed51071cd13 100644
--- a/test/SemaCXX/attr-require-constant-initialization.cpp
+++ b/test/SemaCXX/attr-require-constant-initialization.cpp
@@ -81,16 +81,16 @@ ATTR __thread const int &glvalue_ref_tl = glvalue_int;
void test_basic_start_static_2_1() {
const int non_global = 42;
ATTR static const int &local_init = non_global; // expected-error {{variable does not have a constant initializer}}
- // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+ // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR static const int &global_init = glvalue_int;
ATTR static const int &temp_init = 42;
}
ATTR const int &temp_ref = 42;
ATTR const int &temp_ref2 = ReturnInt(); // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
#if __cplusplus >= 201103L
ATTR const LitType &lit_temp_ref = 42;
@@ -98,7 +98,7 @@ ATTR const int &subobj_ref = LitType{}.value;
#endif
ATTR const int &nl_subobj_ref = NonLit().value; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
struct TT1 {
ATTR static const int &no_init;
@@ -107,7 +107,7 @@ struct TT1 {
ATTR static const int &subobj_init;
#if __cplusplus >= 201103L
ATTR static thread_local const int &tl_glvalue_init;
- ATTR static thread_local const int &tl_temp_init; // expected-note {{required by 'require_constant_initializer' attribute here}}
+ ATTR static thread_local const int &tl_temp_init; // expected-note {{required by 'require_constant_initialization' attribute here}}
#endif
};
const int &TT1::glvalue_init = glvalue_int;
@@ -128,18 +128,18 @@ void test_basic_start_static_2_2() {
ATTR static PODType pod;
#else
ATTR static PODType pod; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
#endif
ATTR static PODType pot2 = {ReturnInt()}; // expected-error {{variable does not have a constant initializer}}
- // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+ // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
#if __cplusplus >= 201103L
constexpr LitType l;
ATTR static LitType static_lit = l;
ATTR static LitType static_lit2 = (void *)0; // expected-error {{variable does not have a constant initializer}}
- // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+ // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR static LitType static_lit3 = ReturnInt(); // expected-error {{variable does not have a constant initializer}}
- // expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+ // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR thread_local LitType tls = 42;
#endif
}
@@ -147,14 +147,14 @@ void test_basic_start_static_2_2() {
struct TT2 {
ATTR static PODType pod_noinit;
#if __cplusplus >= 201103L
-// expected-note@-2 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{required by 'require_constant_initialization' attribute here}}
#endif
- ATTR static PODType pod_copy_init; // expected-note {{required by 'require_constant_initializer' attribute here}}
+ ATTR static PODType pod_copy_init; // expected-note {{required by 'require_constant_initialization' attribute here}}
#if __cplusplus >= 201402L
ATTR static constexpr LitType lit = {};
ATTR static const NonLit non_lit;
ATTR static const NonLit non_lit_list_init;
- ATTR static const NonLit non_lit_copy_init; // expected-note {{required by 'require_constant_initializer' attribute here}}
+ ATTR static const NonLit non_lit_copy_init; // expected-note {{required by 'require_constant_initialization' attribute here}}
#endif
};
PODType TT2::pod_noinit;
@@ -182,20 +182,20 @@ ATTR thread_local NonLit nl_ctor_tl = {};
ATTR StoresNonLit snl;
#else
ATTR NonLit nl_ctor; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR NonLit nl_ctor2{}; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR NonLit nl_ctor3 = {}; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR thread_local NonLit nl_ctor_tl = {}; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR StoresNonLit snl; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
#endif
// Non-literal types cannot appear in the initializer of a non-literal type.
ATTR int nl_in_init = NonLit{42}.value; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR int lit_in_init = LitType{42}.value;
#endif
@@ -217,7 +217,7 @@ ATTR PODType pod_init = {};
ATTR PODType pod_missing_init = {42 /* should have second arg */};
ATTR PODType pod_full_init = {1, 2};
ATTR PODType pod_non_constexpr_init = {1, ReturnInt()}; // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
#if __cplusplus >= 201103L
ATTR int val_init{};
@@ -241,7 +241,7 @@ struct TestCtor {
T value;
};
ATTR TestCtor<NotC> t(42); // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
#endif
// Test various array types
@@ -260,10 +260,10 @@ struct TestCtor {
};
ATTR LitType non_const_lit(nullptr); // expected-error {{variable does not have a constant initializer}}
-// expected-note@-1 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
ATTR NonLit non_const(nullptr); // expected-error {{variable does not have a constant initializer}}
// expected-warning@-1 {{declaration requires a global destructor}}
-// expected-note@-2 {{required by 'require_constant_initializer' attribute here}}
+// expected-note@-2 {{required by 'require_constant_initialization' attribute here}}
LitType const_init_lit(nullptr); // expected-warning {{declaration requires a global constructor}}
NonLit const_init{42}; // expected-warning {{declaration requires a global destructor}}
constexpr TestCtor<NotC> inval_constexpr(42); // expected-error {{must be initialized by a constant expression}}
diff --git a/test/SemaCXX/auto-cxx0x.cpp b/test/SemaCXX/auto-cxx0x.cpp
index f3daf1a19f3c..074a01bb839a 100644
--- a/test/SemaCXX/auto-cxx0x.cpp
+++ b/test/SemaCXX/auto-cxx0x.cpp
@@ -6,3 +6,12 @@ void f() {
}
typedef auto PR25449(); // expected-error {{'auto' not allowed in typedef}}
+
+thread_local auto x; // expected-error {{requires an initializer}}
+
+void g() {
+ [](auto){}(0);
+#if __cplusplus == 201103L
+ // expected-error@-2 {{'auto' not allowed in lambda parameter}}
+#endif
+}
diff --git a/test/SemaCXX/calling-conv-compat.cpp b/test/SemaCXX/calling-conv-compat.cpp
index 20d93b41e1d2..4c4cc15f165a 100644
--- a/test/SemaCXX/calling-conv-compat.cpp
+++ b/test/SemaCXX/calling-conv-compat.cpp
@@ -179,31 +179,31 @@ typedef void ( C::*memb_c_default)();
typedef void (__cdecl C::*memb_c_cdecl)();
typedef void (__thiscall C::*memb_c_thiscall)();
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_default' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'NonVariadic::memb_a_default' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_a_default(memb_a_default ptr);
-// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
void cb_memb_a_cdecl(memb_a_cdecl ptr);
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_thiscall' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'NonVariadic::memb_a_thiscall' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_a_thiscall(memb_a_thiscall ptr);
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_default' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'NonVariadic::memb_b_default' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_b_default(memb_b_default ptr);
-// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
void cb_memb_b_cdecl(memb_b_cdecl ptr);
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_thiscall' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'NonVariadic::memb_b_thiscall' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_b_thiscall(memb_b_thiscall ptr);
-// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
-// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'NonVariadic::memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_c_default(memb_c_default ptr);
-// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
-// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'NonVariadic::memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
void cb_memb_c_cdecl(memb_c_cdecl ptr);
-// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
-// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'NonVariadic::memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'NonVariadic::memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_c_thiscall(memb_c_thiscall ptr);
void call_member() {
@@ -270,11 +270,11 @@ void cb_memb_a_default(memb_a_default ptr);
void cb_memb_a_cdecl(memb_a_cdecl ptr);
void cb_memb_b_default(memb_b_default ptr);
void cb_memb_b_cdecl(memb_b_cdecl ptr);
-// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'Variadic::memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'Variadic::memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
void cb_memb_c_default(memb_c_default ptr);
-// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
-// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
+// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'Variadic::memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
+// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'Variadic::memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
void cb_memb_c_cdecl(memb_c_cdecl ptr);
void call_member() {
@@ -319,7 +319,7 @@ mptr_t __stdcall return_mptr_std(short) {
}
void (A::*(*return_fptr_std_mptr(char))(short))(int) {
- return return_mptr_std; // expected-error {{cannot initialize return object of type 'void (MultiChunkDecls::A::*(*)(short))(int) __attribute__((thiscall))' with an lvalue of type 'mptr_t (short) __attribute__((stdcall))'}}
+ return return_mptr_std; // expected-error {{cannot initialize return object of type 'void (MultiChunkDecls::A::*(*)(short))(int) __attribute__((thiscall))' with an lvalue of type 'MultiChunkDecls::mptr_t (short) __attribute__((stdcall))'}}
}
void call_return() {
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 066832440c75..4abbc8e92847 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
+// RUN: %clang_cc1 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
namespace StaticAssertFoldTest {
@@ -1280,6 +1280,15 @@ namespace Atomic {
constexpr TestVar testVar{-1};
static_assert(testVar.value == -1, "");
}
+
+ namespace PR32034 {
+ struct A {};
+ struct B { _Atomic(A) a; };
+ constexpr int n = (B(), B(), 0);
+
+ struct C { constexpr C() {} void *self = this; };
+ constexpr _Atomic(C) c = C();
+ }
}
namespace InstantiateCaseStmt {
@@ -1303,7 +1312,7 @@ namespace ConvertedConstantExpr {
eo = (m +
n // expected-error {{not a constant expression}}
),
- eq = reinterpret_cast<int>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}}
+ eq = reinterpret_cast<long>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}}
};
}
@@ -1420,8 +1429,8 @@ namespace Fold {
// otherwise a constant expression.
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
- constexpr int n = (int)(char*)123; // expected-error {{constant expression}} expected-note {{reinterpret_cast}}
- constexpr int m = fold((int)(char*)123); // ok
+ constexpr int n = (long)(char*)123; // expected-error {{constant expression}} expected-note {{reinterpret_cast}}
+ constexpr int m = fold((long)(char*)123); // ok
static_assert(m == 123, "");
#undef fold
@@ -2136,3 +2145,17 @@ void g() {
} //end ns PR28366
+namespace PointerArithmeticOverflow {
+ int n;
+ int a[1];
+ constexpr int *b = &n + 1 + (long)-1;
+ constexpr int *c = &n + 1 + (unsigned long)-1; // expected-error {{constant expression}} expected-note {{cannot refer to element 1844}}
+ constexpr int *d = &n + 1 - (unsigned long)1;
+ constexpr int *e = a + 1 + (long)-1;
+ constexpr int *f = a + 1 + (unsigned long)-1; // expected-error {{constant expression}} expected-note {{cannot refer to element 1844}}
+ constexpr int *g = a + 1 - (unsigned long)1;
+
+ constexpr int *p = (&n + 1) + (unsigned __int128)-1; // expected-error {{constant expression}} expected-note {{cannot refer to element 3402}}
+ constexpr int *q = (&n + 1) - (unsigned __int128)-1; // expected-error {{constant expression}} expected-note {{cannot refer to element -3402}}
+ constexpr int *r = &(&n + 1)[(unsigned __int128)-1]; // expected-error {{constant expression}} expected-note {{cannot refer to element 3402}}
+}
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp
index dfdf50ad5484..ac4e0fd471ae 100644
--- a/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -977,3 +977,8 @@ void run() { foo(); }
static_assert(sum(Cs) == 'a' + 'b', ""); // expected-error{{not an integral constant expression}} expected-note{{in call to 'sum(Cs)'}}
constexpr int S = sum(Cs); // expected-error{{must be initialized by a constant expression}} expected-note{{in call}}
}
+
+constexpr void PR28739(int n) { // expected-error {{never produces a constant}}
+ int *p = &n;
+ p += (__int128)(unsigned long)-1; // expected-note {{cannot refer to element 18446744073709551615 of non-array object in a constant expression}}
+}
diff --git a/test/SemaCXX/coreturn.cpp b/test/SemaCXX/coreturn.cpp
index 4c41ae95c513..bdad227ea446 100644
--- a/test/SemaCXX/coreturn.cpp
+++ b/test/SemaCXX/coreturn.cpp
@@ -1,39 +1,21 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify -fblocks -Wno-unreachable-code -Wno-unused-value
+#include "Inputs/std-coroutine.h"
+
+using std::experimental::suspend_always;
+using std::experimental::suspend_never;
struct awaitable {
bool await_ready();
- void await_suspend(); // FIXME: coroutine_handle
+ void await_suspend(std::experimental::coroutine_handle<>); // FIXME: coroutine_handle
void await_resume();
} a;
-struct suspend_always {
- bool await_ready() { return false; }
- void await_suspend() {}
- void await_resume() {}
-};
-
-struct suspend_never {
- bool await_ready() { return true; }
- void await_suspend() {}
- void await_resume() {}
-};
-
-namespace std {
-namespace experimental {
-
-template <class Ret, typename... T>
-struct coroutine_traits { using promise_type = typename Ret::promise_type; };
-
-template <class Promise = void>
-struct coroutine_handle {};
-}
-}
-
struct promise_void {
void get_return_object();
suspend_always initial_suspend();
suspend_always final_suspend();
void return_void();
+ void unhandled_exception();
};
struct promise_float {
@@ -41,6 +23,7 @@ struct promise_float {
suspend_always initial_suspend();
suspend_always final_suspend();
void return_void();
+ void unhandled_exception();
};
struct promise_int {
@@ -48,6 +31,7 @@ struct promise_int {
suspend_always initial_suspend();
suspend_always final_suspend();
void return_value(int);
+ void unhandled_exception();
};
template <typename... T>
diff --git a/test/SemaCXX/coroutine-unhandled_exception-warning.cpp b/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
new file mode 100644
index 000000000000..f98e00d1a709
--- /dev/null
+++ b/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify -fblocks -Wno-unreachable-code -Wno-unused-value
+
+#if __has_feature(cxx_exceptions)
+#error This test requires exceptions be disabled
+#endif
+
+#include "Inputs/std-coroutine.h"
+
+using std::experimental::suspend_always;
+using std::experimental::suspend_never;
+
+struct promise_void {
+ void get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void return_void();
+};
+
+template <typename... T>
+struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise_void; };
+
+void test0() { // expected-warning {{'promise_void' is required to declare the member 'unhandled_exception()' when exceptions are enabled}}
+ co_return;
+}
diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp
index 158b1a7c7dd4..e6eaedef4cce 100644
--- a/test/SemaCXX/coroutines.cpp
+++ b/test/SemaCXX/coroutines.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions
void no_coroutine_traits_bad_arg_await() {
co_await a; // expected-error {{include <experimental/coroutine>}}
@@ -16,42 +16,40 @@ void no_coroutine_traits_bad_arg_return() {
// expected-error@-1 {{use of undeclared identifier 'a'}}
}
+void no_coroutine_traits() {
+ co_await 4; // expected-error {{std::experimental::coroutine_traits type was not found; include <experimental/coroutine>}}
+}
+
+namespace std {
+namespace experimental {
+template <typename... T>
+struct coroutine_traits; // expected-note {{declared here}}
+}} // namespace std::experimental
+
+template<typename Promise> struct coro {};
+template <typename Promise, typename... Ps>
+struct std::experimental::coroutine_traits<coro<Promise>, Ps...> {
+ using promise_type = Promise;
+};
struct awaitable {
bool await_ready();
- void await_suspend(); // FIXME: coroutine_handle
+ template <typename F> void await_suspend(F);
void await_resume();
} a;
struct suspend_always {
bool await_ready() { return false; }
- void await_suspend() {}
+ template <typename F> void await_suspend(F);
void await_resume() {}
};
struct suspend_never {
bool await_ready() { return true; }
- void await_suspend() {}
+ template <typename F> void await_suspend(F);
void await_resume() {}
};
-void no_coroutine_traits() {
- co_await a; // expected-error {{need to include <experimental/coroutine>}}
-}
-
-namespace std {
-namespace experimental {
-template <typename... T>
-struct coroutine_traits; // expected-note {{declared here}}
-}
-}
-
-template<typename Promise> struct coro {};
-template <typename Promise, typename... Ps>
-struct std::experimental::coroutine_traits<coro<Promise>, Ps...> {
- using promise_type = Promise;
-};
-
void no_specialization() {
co_await a; // expected-error {{implicit instantiation of undefined template 'std::experimental::coroutine_traits<void>'}}
}
@@ -59,25 +57,25 @@ void no_specialization() {
template <typename... T>
struct std::experimental::coroutine_traits<int, T...> {};
-int no_promise_type() {
- co_await a; // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int>' has no member named 'promise_type'}}
+int no_promise_type() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int>' has no member named 'promise_type'}}
+ co_await a;
}
template <>
struct std::experimental::coroutine_traits<double, double> { typedef int promise_type; };
-double bad_promise_type(double) {
- co_await a; // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
+double bad_promise_type(double) { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
+ co_await a;
}
template <>
struct std::experimental::coroutine_traits<double, int> {
struct promise_type {};
};
-double bad_promise_type_2(int) {
+double bad_promise_type_2(int) { // expected-error {{no member named 'initial_suspend'}}
co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits<double, int>::promise_type'}}
}
-struct promise; // expected-note 2{{forward declaration}}
+struct promise; // expected-note {{forward declaration}}
struct promise_void;
struct void_tag {};
template <typename... T>
@@ -86,17 +84,8 @@ template <typename... T>
struct std::experimental::coroutine_traits<void, void_tag, T...>
{ using promise_type = promise_void; };
-namespace std {
-namespace experimental {
-template <typename Promise = void>
-struct coroutine_handle;
-}
-}
-
// FIXME: This diagnostic is terrible.
-void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}}
- // FIXME: This diagnostic doesn't make any sense.
- // expected-error@-2 {{incomplete definition of type 'promise'}}
+void undefined_promise() { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<void>::promise_type' (aka 'promise') is an incomplete type}}
co_await a;
}
@@ -112,6 +101,7 @@ struct promise {
awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
not_awaitable yield_value(void()); // expected-note 2{{candidate}}
void return_value(int); // expected-note 2{{here}}
+ void unhandled_exception();
};
struct promise_void {
@@ -119,7 +109,27 @@ struct promise_void {
suspend_always initial_suspend();
suspend_always final_suspend();
void return_void();
+ void unhandled_exception();
+};
+
+void no_coroutine_handle() { // expected-error {{std::experimental::coroutine_handle type was not found; include <experimental/coroutine> before defining a coroutine}}
+ //expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+ co_return 5; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+namespace std {
+namespace experimental {
+template <class PromiseType = void>
+struct coroutine_handle {
+ static coroutine_handle from_address(void *);
};
+template <>
+struct coroutine_handle<void> {
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>);
+ static coroutine_handle from_address(void *);
+};
+}} // namespace std::experimental
void yield() {
co_yield 0;
@@ -143,16 +153,70 @@ void coreturn(int n) {
co_return 42;
}
+template <class T>
+void co_await_non_dependent_arg(T) {
+ co_await a;
+}
+template void co_await_non_dependent_arg(int);
+
void mixed_yield() {
co_yield 0; // expected-note {{use of 'co_yield'}}
return; // expected-error {{not allowed in coroutine}}
}
+void mixed_yield_invalid() {
+ co_yield blah; // expected-error {{use of undeclared identifier}}
+ // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}}
+ return; // expected-error {{return statement not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_yield_template(T) {
+ co_yield blah; // expected-error {{use of undeclared identifier}}
+ // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}}
+ return; // expected-error {{return statement not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_yield_template2(T) {
+ co_yield 42;
+ // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}}
+ return; // expected-error {{return statement not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_yield_template3(T v) {
+ co_yield blah(v);
+ // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}}
+ return; // expected-error {{return statement not allowed in coroutine}}
+}
+
void mixed_await() {
co_await a; // expected-note {{use of 'co_await'}}
return; // expected-error {{not allowed in coroutine}}
}
+void mixed_await_invalid() {
+ co_await 42; // expected-error {{'int' is not a structure or union}}
+ // expected-note@-1 {{function is a coroutine due to use of 'co_await'}}
+ return; // expected-error {{not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_await_template(T) {
+ co_await 42;
+ // expected-note@-1 {{function is a coroutine due to use of 'co_await'}}
+ return; // expected-error {{not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_await_template2(T v) {
+ co_await v; // expected-error {{'long' is not a structure or union}}
+ // expected-note@-1 {{function is a coroutine due to use of 'co_await'}}
+ return; // expected-error {{not allowed in coroutine}}
+}
+template void mixed_await_template2(long); // expected-note {{requested here}}
+
void only_coreturn(void_tag) {
co_return; // OK
}
@@ -164,6 +228,33 @@ void mixed_coreturn(void_tag, bool b) {
return; // expected-error {{not allowed in coroutine}}
}
+void mixed_coreturn_invalid(bool b) {
+ if (b)
+ co_return; // expected-note {{use of 'co_return'}}
+ // expected-error@-1 {{no member named 'return_void' in 'promise'}}
+ else
+ return; // expected-error {{not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_coreturn_template(void_tag, bool b, T v) {
+ if (b)
+ co_return v; // expected-note {{use of 'co_return'}}
+ // expected-error@-1 {{no member named 'return_value' in 'promise_void'}}
+ else
+ return; // expected-error {{not allowed in coroutine}}
+}
+template void mixed_coreturn_template(void_tag, bool, int); // expected-note {{requested here}}
+
+template <class T>
+void mixed_coreturn_template2(bool b, T) {
+ if (b)
+ co_return v; // expected-note {{use of 'co_return'}}
+ // expected-error@-1 {{use of undeclared identifier 'v'}}
+ else
+ return; // expected-error {{not allowed in coroutine}}
+}
+
struct CtorDtor {
CtorDtor() {
co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}}
@@ -216,6 +307,13 @@ auto deduced_return_coroutine() {
}
struct outer {};
+struct await_arg_1 {};
+struct await_arg_2 {};
+
+namespace adl_ns {
+struct coawait_arg_type {};
+awaitable operator co_await(coawait_arg_type);
+}
namespace dependent_operator_co_await_lookup {
template<typename T> void await_template(T t) {
@@ -238,6 +336,96 @@ namespace dependent_operator_co_await_lookup {
};
template void await_template(outer); // expected-note {{instantiation}}
template void await_template_2(outer);
+
+ struct transform_awaitable {};
+ struct transformed {};
+
+ struct transform_promise {
+ typedef transform_awaitable await_arg;
+ coro<transform_promise> get_return_object();
+ transformed initial_suspend();
+ ::adl_ns::coawait_arg_type final_suspend();
+ transformed await_transform(transform_awaitable);
+ void unhandled_exception();
+ };
+ template <class AwaitArg>
+ struct basic_promise {
+ typedef AwaitArg await_arg;
+ coro<basic_promise> get_return_object();
+ awaitable initial_suspend();
+ awaitable final_suspend();
+ void unhandled_exception();
+ };
+
+ awaitable operator co_await(await_arg_1);
+
+ template <typename T, typename U>
+ coro<T> await_template_3(U t) {
+ co_await t;
+ }
+
+ template coro<basic_promise<await_arg_1>> await_template_3<basic_promise<await_arg_1>>(await_arg_1);
+
+ template <class T, int I = 0>
+ struct dependent_member {
+ coro<T> mem_fn() const {
+ co_await typename T::await_arg{}; // expected-error {{call to function 'operator co_await'}}}
+ }
+ template <class U>
+ coro<T> dep_mem_fn(U t) {
+ co_await t;
+ }
+ };
+
+ template <>
+ struct dependent_member<long> {
+ // FIXME this diagnostic is terrible
+ coro<transform_promise> mem_fn() const { // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::transformed'}}
+ // expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+ // expected-note@+1 {{function is a coroutine due to use of 'co_await' here}}
+ co_await transform_awaitable{};
+ // expected-error@-1 {{no member named 'await_ready'}}
+ }
+ template <class R, class U>
+ coro<R> dep_mem_fn(U u) { co_await u; }
+ };
+
+ awaitable operator co_await(await_arg_2); // expected-note {{'operator co_await' should be declared prior to the call site}}
+
+ template struct dependent_member<basic_promise<await_arg_1>, 0>;
+ template struct dependent_member<basic_promise<await_arg_2>, 0>; // expected-note {{in instantiation}}
+
+ template <>
+ coro<transform_promise>
+ // FIXME this diagnostic is terrible
+ dependent_member<long>::dep_mem_fn<transform_promise>(int) { // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::transformed'}}
+ //expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+ //expected-note@+1 {{function is a coroutine due to use of 'co_await' here}}
+ co_await transform_awaitable{};
+ // expected-error@-1 {{no member named 'await_ready'}}
+ }
+
+ void operator co_await(transform_awaitable) = delete;
+ awaitable operator co_await(transformed);
+
+ template coro<transform_promise>
+ dependent_member<long>::dep_mem_fn<transform_promise>(transform_awaitable);
+
+ template <>
+ coro<transform_promise> dependent_member<long>::dep_mem_fn<transform_promise>(long) {
+ co_await transform_awaitable{};
+ }
+
+ template <>
+ struct dependent_member<int> {
+ coro<transform_promise> mem_fn() const {
+ co_await transform_awaitable{};
+ }
+ };
+
+ template coro<transform_promise> await_template_3<transform_promise>(transform_awaitable);
+ template struct dependent_member<transform_promise>;
+ template coro<transform_promise> dependent_member<transform_promise>::dep_mem_fn(transform_awaitable);
}
struct yield_fn_tag {};
@@ -251,6 +439,7 @@ struct std::experimental::coroutine_traits<void, yield_fn_tag> {
suspend_never initial_suspend();
suspend_never final_suspend();
void get_return_object();
+ void unhandled_exception();
};
};
@@ -283,6 +472,7 @@ namespace placeholder {
struct bad_promise_1 {
suspend_always initial_suspend();
suspend_always final_suspend();
+ void unhandled_exception();
};
coro<bad_promise_1> missing_get_return_object() { // expected-error {{no member named 'get_return_object' in 'bad_promise_1'}}
co_await a;
@@ -292,7 +482,9 @@ struct bad_promise_2 {
coro<bad_promise_2> get_return_object();
// FIXME: We shouldn't offer a typo-correction here!
suspend_always final_suspend(); // expected-note {{here}}
+ void unhandled_exception();
};
+// FIXME: This shouldn't happen twice
coro<bad_promise_2> missing_initial_suspend() { // expected-error {{no member named 'initial_suspend' in 'bad_promise_2'}}
co_await a;
}
@@ -301,6 +493,7 @@ struct bad_promise_3 {
coro<bad_promise_3> get_return_object();
// FIXME: We shouldn't offer a typo-correction here!
suspend_always initial_suspend(); // expected-note {{here}}
+ void unhandled_exception();
};
coro<bad_promise_3> missing_final_suspend() { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}}
co_await a;
@@ -313,7 +506,8 @@ struct bad_promise_4 {
};
// FIXME: This diagnostic is terrible.
coro<bad_promise_4> bad_initial_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
- co_await a;
+ // expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+ co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}}
}
struct bad_promise_5 {
@@ -323,13 +517,15 @@ struct bad_promise_5 {
};
// FIXME: This diagnostic is terrible.
coro<bad_promise_5> bad_final_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
- co_await a;
+ // expected-note@-1 {{call to 'final_suspend' implicitly required by the final suspend point}}
+ co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}}
}
struct bad_promise_6 {
coro<bad_promise_6> get_return_object();
suspend_always initial_suspend();
suspend_always final_suspend();
+ void unhandled_exception();
void return_void();
void return_value(int) const;
void return_value(int);
@@ -338,39 +534,163 @@ coro<bad_promise_6> bad_implicit_return() { // expected-error {{'bad_promise_6'
co_await a;
}
+template <class T>
+coro<T> bad_implicit_return_dependent(T) { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}}
+ co_await a;
+}
+template coro<bad_promise_6> bad_implicit_return_dependent(bad_promise_6); // expected-note {{in instantiation}}
+
struct bad_promise_7 {
coro<bad_promise_7> get_return_object();
suspend_always initial_suspend();
suspend_always final_suspend();
void return_void();
- void set_exception(int *);
};
-coro<bad_promise_7> no_std_current_exc() {
- // expected-error@-1 {{you need to include <exception> before defining a coroutine that implicitly uses 'set_exception'}}
+coro<bad_promise_7> no_unhandled_exception() { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}}
co_await a;
}
-namespace std {
-int *current_exception();
+template <class T>
+coro<T> no_unhandled_exception_dependent(T) { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}}
+ co_await a;
}
+template coro<bad_promise_7> no_unhandled_exception_dependent(bad_promise_7); // expected-note {{in instantiation}}
-struct bad_promise_8 {
+struct bad_promise_base {
+private:
+ void return_void();
+};
+struct bad_promise_8 : bad_promise_base {
coro<bad_promise_8> get_return_object();
suspend_always initial_suspend();
suspend_always final_suspend();
- void return_void();
- void set_exception(); // expected-note {{function not viable}}
- void set_exception(int *) __attribute__((unavailable)); // expected-note {{explicitly made unavailable}}
- void set_exception(void *); // expected-note {{candidate function}}
+ void unhandled_exception() __attribute__((unavailable)); // expected-note 2 {{made unavailable}}
+ void unhandled_exception() const; // expected-note 2 {{candidate}}
+ void unhandled_exception(void *) const; // expected-note 2 {{requires 1 argument, but 0 were provided}}
};
-coro<bad_promise_8> calls_set_exception() {
- // expected-error@-1 {{call to unavailable member function 'set_exception'}}
+coro<bad_promise_8> calls_unhandled_exception() {
+ // expected-error@-1 {{call to unavailable member function 'unhandled_exception'}}
+ // FIXME: also warn about private 'return_void' here. Even though building
+ // the call to unhandled_exception has already failed.
co_await a;
}
+template <class T>
+coro<T> calls_unhandled_exception_dependent(T) {
+ // expected-error@-1 {{call to unavailable member function 'unhandled_exception'}}
+ co_await a;
+}
+template coro<bad_promise_8> calls_unhandled_exception_dependent(bad_promise_8); // expected-note {{in instantiation}}
+
+struct bad_promise_9 {
+ coro<bad_promise_9> get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void await_transform(void *); // expected-note {{candidate}}
+ awaitable await_transform(int) __attribute__((unavailable)); // expected-note {{explicitly made unavailable}}
+ void return_void();
+ void unhandled_exception();
+};
+coro<bad_promise_9> calls_await_transform() {
+ co_await 42; // expected-error {{call to unavailable member function 'await_transform'}}
+ // expected-note@-1 {{call to 'await_transform' implicitly required by 'co_await' here}}
+}
+
+struct bad_promise_10 {
+ coro<bad_promise_10> get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ int await_transform;
+ void return_void();
+ void unhandled_exception();
+};
+coro<bad_promise_10> bad_coawait() {
+ // FIXME this diagnostic is terrible
+ co_await 42; // expected-error {{called object type 'int' is not a function or function pointer}}
+ // expected-note@-1 {{call to 'await_transform' implicitly required by 'co_await' here}}
+}
+
+struct call_operator {
+ template <class... Args>
+ awaitable operator()(Args...) const { return a; }
+};
+void ret_void();
+struct good_promise_1 {
+ coro<good_promise_1> get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+ static const call_operator await_transform;
+ using Fn = void (*)();
+ Fn return_void = ret_void;
+};
+const call_operator good_promise_1::await_transform;
+coro<good_promise_1> ok_static_coawait() {
+ // FIXME this diagnostic is terrible
+ co_await 42;
+}
+
template<> struct std::experimental::coroutine_traits<int, int, const char**>
{ using promise_type = promise; };
int main(int, const char**) {
co_await a; // expected-error {{'co_await' cannot be used in the 'main' function}}
}
+
+struct good_promise_2 {
+ float get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void return_void();
+ void unhandled_exception();
+};
+template<> struct std::experimental::coroutine_handle<good_promise_2> {};
+
+template<> struct std::experimental::coroutine_traits<float>
+{ using promise_type = good_promise_2; };
+
+float badly_specialized_coro_handle() { // expected-error {{std::experimental::coroutine_handle missing a member named 'from_address'}}
+ //expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+ co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct promise_on_alloc_failure_tag {};
+
+template<>
+struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> {
+ struct promise_type {
+ int get_return_object() {}
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() { return {}; }
+ void return_void() {}
+ int get_return_object_on_allocation_failure(); // expected-error{{'promise_type': 'get_return_object_on_allocation_failure()' must be a static member function}}
+ void unhandled_exception();
+ };
+};
+
+extern "C" int f(promise_on_alloc_failure_tag) {
+ co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct bad_promise_11 {
+ coro<bad_promise_11> get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+ void return_void();
+
+private:
+ static coro<bad_promise_11> get_return_object_on_allocation_failure(); // expected-note 2 {{declared private here}}
+};
+coro<bad_promise_11> private_alloc_failure_handler() {
+ // expected-error@-1 {{'get_return_object_on_allocation_failure' is a private member of 'bad_promise_11'}}
+ co_return; // FIXME: Add a "declared coroutine here" note.
+}
+
+template <class T>
+coro<T> dependent_private_alloc_failure_handler(T) {
+ // expected-error@-1 {{'get_return_object_on_allocation_failure' is a private member of 'bad_promise_11'}}
+ co_return; // FIXME: Add a "declared coroutine here" note.
+}
+template coro<bad_promise_11> dependent_private_alloc_failure_handler(bad_promise_11);
+// expected-note@-1 {{requested here}}
diff --git a/test/SemaCXX/cxx-altivec.cpp b/test/SemaCXX/cxx-altivec.cpp
index baacbac7d036..50fb8ad014c2 100644
--- a/test/SemaCXX/cxx-altivec.cpp
+++ b/test/SemaCXX/cxx-altivec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple=powerpc-apple-darwin8 -faltivec -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple=powerpc-apple-darwin8 -target-feature +altivec -fsyntax-only -verify %s
struct Vector {
__vector float xyzw;
diff --git a/test/SemaCXX/cxx0x-class.cpp b/test/SemaCXX/cxx0x-class.cpp
index 8afb0fd6f3c0..c0e80daaba5d 100644
--- a/test/SemaCXX/cxx0x-class.cpp
+++ b/test/SemaCXX/cxx0x-class.cpp
@@ -45,3 +45,11 @@ class DefaultMemberInitSelf {
DefaultMemberTemplate<int> t = {};
int *p = &t.n;
};
+
+namespace composed_templates {
+ // Regression test -- obtaining the type from composed templates should not
+ // require out-of-line definition.
+ template <typename T> struct Zero { static const typename T::type value = 0; };
+ struct Integer { using type = int; };
+ template struct Zero<Integer>;
+}
diff --git a/test/SemaCXX/cxx0x-initializer-aggregates.cpp b/test/SemaCXX/cxx0x-initializer-aggregates.cpp
index 1b01a351f781..7a7b92b7d04f 100644
--- a/test/SemaCXX/cxx0x-initializer-aggregates.cpp
+++ b/test/SemaCXX/cxx0x-initializer-aggregates.cpp
@@ -127,7 +127,7 @@ namespace multidimensional_array {
namespace array_addressof {
using T = int[5];
- T *p = &T{1,2,3,4,5}; // expected-error {{taking the address of a temporary object of type 'T' (aka 'int [5]')}}
+ T *p = &T{1,2,3,4,5}; // expected-error {{taking the address of a temporary object of type 'array_addressof::T' (aka 'int [5]')}}
}
namespace PR24816 {
diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp
index c10bee917ac0..07a233b56ce1 100644
--- a/test/SemaCXX/cxx0x-initializer-constructor.cpp
+++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp
@@ -173,8 +173,7 @@ namespace objects {
// invalid
H h1({1, 2}); // expected-error {{no matching constructor}}
(void) new H({1, 2}); // expected-error {{no matching constructor}}
- // FIXME: Bad diagnostic, mentions void type instead of init list.
- (void) H({1, 2}); // expected-error {{no matching conversion}}
+ (void) H({1, 2}); // expected-error {{no matching constructor}}
// valid (by copy constructor).
H h2({1, nullptr});
diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp
index c64511193b6e..ce029d7f0732 100644
--- a/test/SemaCXX/cxx0x-initializer-references.cpp
+++ b/test/SemaCXX/cxx0x-initializer-references.cpp
@@ -71,10 +71,22 @@ namespace reference {
static_assert(sizeof(h({1, 2})) == sizeof(two), "bad overload resolution");
}
+ struct X {};
+
void edge_cases() {
- int const &b({0}); // expected-error {{list-initializer for non-class type 'const int &' must not be parenthesized}}
- const int (&arr)[3] ({1, 2, 3}); // expected-error {{list-initializer for non-class type 'const int (&)[3]' must not be parenthesized}}
+ int const &b({0}); // expected-error {{cannot initialize reference type 'const int &' with a parenthesized initializer list}}
+ const int (&arr)[3] ({1, 2, 3}); // expected-error {{cannot initialize reference type 'const int (&)[3]' with a parenthesized initializer list}}
+ const X &x({}); // expected-error {{cannot initialize reference type 'const reference::X &' with a parenthesized initializer list}}
+ }
+
+ template<typename T> void dependent_edge_cases() {
+ T b({}); // expected-error-re 3{{cannot initialize reference type {{.*}} with a parenthesized init}}
+ T({}); // expected-error-re 3{{cannot initialize reference type {{.*}} with a parenthesized init}}
}
+ template void dependent_edge_cases<X>(); // ok
+ template void dependent_edge_cases<const int&>(); // expected-note {{instantiation of}}
+ template void dependent_edge_cases<const int(&)[1]>(); // expected-note {{instantiation of}}
+ template void dependent_edge_cases<const X&>(); // expected-note {{instantiation of}}
}
namespace PR12182 {
diff --git a/test/SemaCXX/cxx0x-initializer-scalars.cpp b/test/SemaCXX/cxx0x-initializer-scalars.cpp
index 65b57a5584ab..90b11f3a9e23 100644
--- a/test/SemaCXX/cxx0x-initializer-scalars.cpp
+++ b/test/SemaCXX/cxx0x-initializer-scalars.cpp
@@ -91,13 +91,13 @@ namespace integral {
}
void edge_cases() {
- int a({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
- (void) int({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
- new int({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
+ int a({0}); // expected-error {{cannot initialize non-class type 'int' with a parenthesized initializer list}}
+ (void) int({0}); // expected-error {{cannot initialize non-class type 'int' with a parenthesized initializer list}}
+ new int({0}); // expected-error {{cannot initialize non-class type 'int' with a parenthesized initializer list}}
- int *b({0}); // expected-error {{list-initializer for non-class type 'int *' must not be parenthesized}}
+ int *b({0}); // expected-error {{cannot initialize non-class type 'int *' with a parenthesized initializer list}}
typedef int *intptr;
- int *c = intptr({0}); // expected-error {{list-initializer for non-class type 'intptr' (aka 'int *') must not be parenthesized}}
+ int *c = intptr({0}); // expected-error {{cannot initialize non-class type 'intptr' (aka 'int *') with a parenthesized initializer list}}
}
template<typename T> void dependent_edge_cases() {
diff --git a/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp b/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
index 58bbbb2a0442..c7e6074a4437 100644
--- a/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
+++ b/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
@@ -172,6 +172,6 @@ namespace extended_examples_array_bounds {
#ifdef CXX1Y
#else
//expected-error@168 {{ambiguous conversion of array size expression of type 'extended_examples_array_bounds::Foo' to an integral or enumeration type}}
-//expected-note@162 {{conversion to integral type 'size_t'}}
+//expected-note@162 {{conversion to integral type 'extended_examples_array_bounds::size_t'}}
//expected-note@163 {{conversion to integral type 'unsigned short' declared here}}
#endif
diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp
index 593ec48b4394..bfe0ab9dcdbc 100644
--- a/test/SemaCXX/cxx1y-deduced-return-type.cpp
+++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp
@@ -314,7 +314,7 @@ namespace NoReturn {
}
namespace UseBeforeComplete {
- auto n = n; // expected-error {{variable 'n' declared with 'auto' type cannot appear in its own initializer}}
+ auto n = n; // expected-error {{variable 'n' declared with deduced type 'auto' cannot appear in its own initializer}}
auto f(); // expected-note {{declared here}}
void g() { &f; } // expected-error {{function 'f' with deduced return type cannot be used before it is defined}}
auto sum(int i) {
@@ -385,6 +385,33 @@ namespace MemberTemplatesWithDeduction {
}
}
+// We resolve a wording bug here: 'decltype(auto)' should not be modeled as a
+// decltype-specifier, just as a simple-type-specifier. All the extra places
+// where a decltype-specifier can appear make no sense for 'decltype(auto)'.
+namespace DecltypeAutoShouldNotBeADecltypeSpecifier {
+ namespace NNS {
+ int n;
+ decltype(auto) i();
+ decltype(n) j();
+ struct X {
+ friend decltype(auto) ::DecltypeAutoShouldNotBeADecltypeSpecifier::NNS::i();
+ friend decltype(n) ::DecltypeAutoShouldNotBeADecltypeSpecifier::NNS::j(); // expected-error {{not a class}}
+ };
+ }
+
+ namespace Dtor {
+ struct A {};
+ void f(A a) { a.~decltype(auto)(); } // expected-error {{'decltype(auto)' not allowed here}}
+ }
+
+ namespace BaseClass {
+ struct A : decltype(auto) {}; // expected-error {{'decltype(auto)' not allowed here}}
+ struct B {
+ B() : decltype(auto)() {} // expected-error {{'decltype(auto)' not allowed here}}
+ };
+ }
+}
+
namespace CurrentInstantiation {
// PR16875
template<typename T> struct S {
diff --git a/test/SemaCXX/cxx1y-generic-lambdas.cpp b/test/SemaCXX/cxx1y-generic-lambdas.cpp
index 3774e8d3834b..1993c6e1853d 100644
--- a/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ b/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -912,7 +912,7 @@ struct X1 {
template<class T>
template<class U>
int X1::X2<T>::fooG3(T (*fp)(U)) { return 0; }
-X1::X2<int> x2; //expected-note 3{{in instantiation of}}
+X1::X2<int> x2; //expected-note {{in instantiation of}}
int run1 = x2.fooG2();
int run2 = x2.fooG3();
} // end ns
diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
index 76f1bb9905b9..66f0f10f0f3d 100644
--- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
+++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -17,8 +17,7 @@ class A {
template<typename T> CONST float right<float,T> = 5; // expected-error {{member 'right' declared as a template}}
template<> static CONST int right<int,int> = 7; // expected-error {{explicit specialization of 'right' in class scope}}
template<> static CONST float right<float,int>; // expected-error {{explicit specialization of 'right' in class scope}}
- template static CONST int right<int,int>; // expected-error {{template specialization requires 'template<>'}} \
- // expected-error {{explicit specialization of 'right' in class scope}}
+ template static CONST int right<int,int>; // expected-error {{expected '<' after 'template'}}
};
namespace out_of_line {
@@ -166,8 +165,7 @@ namespace constexpred {
template<typename T> constexpr float right<float,T> = 5; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
template<> static constexpr int right<int,int> = 7; // expected-error {{explicit specialization of 'right' in class scope}}
template<> static constexpr float right<float,int>; // expected-error {{explicit specialization of 'right' in class scope}}
- template static constexpr int right<int,int>; // expected-error {{template specialization requires 'template<>'}} \
- // expected-error {{explicit specialization of 'right' in class scope}}
+ template static constexpr int right<int,int>; // expected-error {{expected '<' after 'template'}}
};
}
#endif
diff --git a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
index 367f67bf5fa8..b4963646838c 100644
--- a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
+++ b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
@@ -102,7 +102,7 @@ namespace odr_tmpl {
template<typename T> extern int v; // expected-error {{redeclaration of 'v' with a different type: 'int' vs 'T'}}
#ifndef PRECXX11
- template<typename T> extern auto v; // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}}
+ template<typename T> extern auto v; // expected-error {{declaration of variable 'v' with deduced type 'auto' requires an initializer}}
#endif
template<typename T> T var = T(); // expected-note {{previous definition is here}}
@@ -111,7 +111,7 @@ namespace odr_tmpl {
#ifndef PRECXX11
namespace pvt_auto {
- template<typename T> auto v0; // expected-error {{declaration of variable 'v0' with type 'auto' requires an initializer}}
+ template<typename T> auto v0; // expected-error {{declaration of variable 'v0' with deduced type 'auto' requires an initializer}}
template<typename T> auto v1 = T(); // expected-note {{previous definition is here}}
template<typename T> int v1; // expected-error {{redefinition of 'v1' with a different type: 'int' vs 'auto'}}
template<typename T> auto v2 = T(); // expected-note {{previous definition is here}}
@@ -119,7 +119,7 @@ namespace odr_tmpl {
template<typename T> auto v3 = T(); // expected-note {{previous definition is here}}
template<typename T> extern T v3; // expected-error {{redeclaration of 'v3' with a different type: 'T' vs 'auto'}}
template<typename T> auto v4 = T();
- template<typename T> extern auto v4; // expected-error {{declaration of variable 'v4' with type 'auto' requires an initializer}}
+ template<typename T> extern auto v4; // expected-error {{declaration of variable 'v4' with deduced type 'auto' requires an initializer}}
}
#endif
diff --git a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
new file mode 100644
index 000000000000..d6374e4ce907
--- /dev/null
+++ b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -0,0 +1,215 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+namespace std {
+ using size_t = decltype(sizeof(0));
+ template<typename T> struct initializer_list {
+ const T *p;
+ size_t n;
+ initializer_list();
+ };
+ // FIXME: This should probably not be necessary.
+ template<typename T> initializer_list(initializer_list<T>) -> initializer_list<T>;
+}
+
+template<typename T> constexpr bool has_type(...) { return false; }
+template<typename T> constexpr bool has_type(T) { return true; }
+
+std::initializer_list il = {1, 2, 3, 4, 5};
+
+template<typename T> struct vector {
+ template<typename Iter> vector(Iter, Iter);
+ vector(std::initializer_list<T>);
+};
+
+template<typename T> vector(std::initializer_list<T>) -> vector<T>;
+template<typename Iter> explicit vector(Iter, Iter) -> vector<typename Iter::value_type>;
+template<typename T> explicit vector(std::size_t, T) -> vector<T>;
+
+vector v1 = {1, 2, 3, 4};
+static_assert(has_type<vector<int>>(v1));
+
+struct iter { typedef char value_type; } it, end;
+vector v2(it, end);
+static_assert(has_type<vector<char>>(v2));
+
+vector v3(5, 5);
+static_assert(has_type<vector<int>>(v3));
+
+vector v4 = {it, end};
+static_assert(has_type<vector<iter>>(v4));
+
+vector v5{it, end};
+static_assert(has_type<vector<iter>>(v5));
+
+template<typename ...T> struct tuple { tuple(T...); };
+template<typename ...T> explicit tuple(T ...t) -> tuple<T...>; // expected-note {{declared}}
+// FIXME: Remove
+template<typename ...T> tuple(tuple<T...>) -> tuple<T...>;
+
+const int n = 4;
+tuple ta = tuple{1, 'a', "foo", n};
+static_assert(has_type<tuple<int, char, const char*, int>>(ta));
+
+tuple tb{ta};
+static_assert(has_type<tuple<int, char, const char*, int>>(tb));
+
+// FIXME: This should be tuple<tuple<...>>; when the above guide is removed.
+tuple tc = {ta};
+static_assert(has_type<tuple<int, char, const char*, int>>(tc));
+
+tuple td = {1, 2, 3}; // expected-error {{selected an explicit deduction guide}}
+static_assert(has_type<tuple<int, char, const char*, int>>(td));
+
+// FIXME: This is a GCC extension for now; if CWG don't allow this, at least
+// add a warning for it.
+namespace new_expr {
+ tuple<int> *p = new tuple{0};
+ tuple<float, float> *q = new tuple(1.0f, 2.0f);
+}
+
+namespace ambiguity {
+ template<typename T> struct A {};
+ A(unsigned short) -> A<int>; // expected-note {{candidate}}
+ A(short) -> A<int>; // expected-note {{candidate}}
+ A a = 0; // expected-error {{ambiguous deduction for template arguments of 'A'}}
+
+ template<typename T> struct B {};
+ template<typename T> B(T(&)(int)) -> B<int>; // expected-note {{candidate function [with T = int]}}
+ template<typename T> B(int(&)(T)) -> B<int>; // expected-note {{candidate function [with T = int]}}
+ int f(int);
+ B b = f; // expected-error {{ambiguous deduction for template arguments of 'B'}}
+}
+
+// FIXME: Revisit this once CWG decides if attributes, and [[deprecated]] in
+// particular, should be permitted here.
+namespace deprecated {
+ template<typename T> struct A { A(int); };
+ [[deprecated]] A(int) -> A<void>; // expected-note {{marked deprecated here}}
+ A a = 0; // expected-warning {{'<deduction guide for A>' is deprecated}}
+}
+
+namespace dependent {
+ template<template<typename...> typename A> decltype(auto) a = A{1, 2, 3};
+ static_assert(has_type<vector<int>>(a<vector>));
+ static_assert(has_type<tuple<int, int, int>>(a<tuple>));
+
+ struct B {
+ template<typename T> struct X { X(T); };
+ X(int) -> X<int>;
+ template<typename T> using Y = X<T>; // expected-note {{template}}
+ };
+ template<typename T> void f() {
+ typename T::X tx = 0;
+ typename T::Y ty = 0; // expected-error {{alias template 'Y' requires template arguments; argument deduction only allowed for class templates}}
+ }
+ template void f<B>(); // expected-note {{in instantiation of}}
+
+ template<typename T> struct C { C(T); };
+ template<typename T> C(T) -> C<T>;
+ template<typename T> void g(T a) {
+ C b = 0;
+ C c = a;
+ using U = decltype(b); // expected-note {{previous}}
+ using U = decltype(c); // expected-error {{different types ('C<const char *>' vs 'C<int>')}}
+ }
+ void h() {
+ g(0);
+ g("foo"); // expected-note {{instantiation of}}
+ }
+}
+
+namespace look_into_current_instantiation {
+ template<typename U> struct Q {};
+ template<typename T> struct A {
+ using U = T;
+ template<typename> using V = Q<A<T>::U>;
+ template<typename W = int> A(V<W>);
+ };
+ A a = Q<float>(); // ok, can look through class-scope typedefs and alias
+ // templates, and members of the current instantiation
+ A<float> &r = a;
+
+ template<typename T> struct B { // expected-note {{could not match 'B<T>' against 'int'}}
+ struct X {
+ typedef T type;
+ };
+ B(typename X::type); // expected-note {{couldn't infer template argument 'T'}}
+ };
+ B b = 0; // expected-error {{no viable}}
+
+ // We should have a substitution failure in the immediate context of
+ // deduction when using the C(T, U) constructor (probably; core wording
+ // unclear).
+ template<typename T> struct C {
+ using U = typename T::type;
+ C(T, U);
+ };
+
+ struct R { R(int); typedef R type; };
+ C(...) -> C<R>;
+
+ C c = {1, 2};
+}
+
+namespace nondeducible {
+ template<typename A, typename B> struct X {};
+
+ template<typename A> // expected-note {{non-deducible template parameter 'A'}}
+ X() -> X<A, int>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}}
+
+ template<typename A> // expected-note {{non-deducible template parameter 'A'}}
+ X(typename X<A, int>::type) -> X<A, int>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}}
+
+ template<typename A = int,
+ typename B> // expected-note {{non-deducible template parameter 'B'}}
+ X(int) -> X<A, B>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}}
+
+ template<typename A = int,
+ typename ...B>
+ X(float) -> X<A, B...>; // ok
+}
+
+namespace default_args_from_ctor {
+ template <class A> struct S { S(A = 0) {} };
+ S s(0);
+
+ template <class A> struct T { template<typename B> T(A = 0, B = 0) {} };
+ T t(0, 0);
+}
+
+namespace transform_params {
+ template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]>
+ struct A {
+ template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W>
+ A(U<X>, W<Y>);
+
+ static constexpr T v = N;
+ };
+
+ int n[12];
+ template<int (*)[12]> struct Q {};
+ Q<&n> qn;
+ A a(qn, qn);
+ static_assert(a.v == 12);
+
+ template<typename ...T> struct B {
+ template<T ...V> B(const T (&...p)[V]) {
+ constexpr int Vs[] = {V...};
+ static_assert(Vs[0] == 3 && Vs[1] == 4 && Vs[2] == 4);
+ }
+ static constexpr int (*p)(T...) = (int(*)(int, char, char))nullptr;
+ };
+ B b({1, 2, 3}, "foo", {'x', 'y', 'z', 'w'}); // ok
+
+ template<typename ...T> struct C {
+ template<T ...V, template<T...> typename X>
+ C(X<V...>);
+ };
+ template<int...> struct Y {};
+ C c(Y<0, 1, 2>{});
+
+ template<typename ...T> struct D {
+ template<T ...V> D(Y<V...>);
+ };
+ D d(Y<0, 1, 2>{});
+}
diff --git a/test/SemaCXX/cxx1z-constexpr-lambdas.cpp b/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
index 16d5730d3d4c..4a98a1b06c87 100644
--- a/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ b/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks %s
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s
-// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks %s -DCPP14_AND_EARLIER
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks %s -fcxx-exceptions
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -fcxx-exceptions
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks %s -DCPP14_AND_EARLIER -fcxx-exceptions
namespace test_lambda_is_literal {
@@ -157,18 +157,115 @@ constexpr auto M = // expected-error{{must be initialized by}}
} // end ns1_simple_lambda
-namespace ns1_unimplemented {
-namespace ns1_captures {
+namespace test_captures_1 {
+namespace ns1 {
constexpr auto f(int i) {
- double d = 3.14;
- auto L = [=](auto a) { //expected-note{{coming soon}}
- int Isz = i + d;
- return sizeof(i) + sizeof(a) + sizeof(d);
+ struct S { int x; } s = { i * 2 };
+ auto L = [=](auto a) {
+ return i + s.x + a;
+ };
+ return L;
+}
+constexpr auto M = f(3);
+
+static_assert(M(10) == 19);
+
+} // end test_captures_1::ns1
+
+namespace ns2 {
+
+constexpr auto foo(int n) {
+ auto L = [i = n] (auto N) mutable {
+ if (!N(i)) throw "error";
+ return [&i] {
+ return ++i;
+ };
};
+ auto M = L([n](int p) { return p == n; });
+ M(); M();
+ L([n](int p) { return p == n + 2; });
+
return L;
}
-constexpr auto M = f(3); //expected-error{{constant expression}} expected-note{{in call to}}
-} // end ns1_captures
+
+constexpr auto L = foo(3);
+
+} // end test_captures_1::ns2
+namespace ns3 {
+
+constexpr auto foo(int n) {
+ auto L = [i = n] (auto N) mutable {
+ if (!N(i)) throw "error";
+ return [&i] {
+ return [i]() mutable {
+ return ++i;
+ };
+ };
+ };
+ auto M = L([n](int p) { return p == n; });
+ M()(); M()();
+ L([n](int p) { return p == n; });
+
+ return L;
+}
+
+constexpr auto L = foo(3);
+} // end test_captures_1::ns3
+
+namespace ns2_capture_this_byval {
+struct S {
+ int s;
+ constexpr S(int s) : s{s} { }
+ constexpr auto f(S o) {
+ return [*this,o] (auto a) { return s + o.s + a.s; };
+ }
+};
+
+constexpr auto L = S{5}.f(S{10});
+static_assert(L(S{100}) == 115);
+} // end test_captures_1::ns2_capture_this_byval
+
+namespace ns2_capture_this_byref {
+
+struct S {
+ int s;
+ constexpr S(int s) : s{s} { }
+ constexpr auto f() const {
+ return [this] { return s; };
+ }
+};
+
+constexpr S SObj{5};
+constexpr auto L = SObj.f();
+constexpr int I = L();
+static_assert(I == 5);
+
+} // end ns2_capture_this_byref
+
+} // end test_captures_1
+
+namespace test_capture_array {
+namespace ns1 {
+constexpr auto f(int I) {
+ int arr[] = { I, I *2, I * 3 };
+ auto L1 = [&] (auto a) { return arr[a]; };
+ int r = L1(2);
+ struct X { int x, y; };
+ return [=](auto a) { return X{arr[a],r}; };
+}
+constexpr auto L = f(3);
+static_assert(L(0).x == 3);
+static_assert(L(0).y == 9);
+static_assert(L(1).x == 6);
+static_assert(L(1).y == 9);
+} // end ns1
+
+} // end test_capture_array
+namespace ns1_test_lvalue_type {
+ void f() {
+ volatile int n;
+ constexpr bool B = [&]{ return &n; }() == &n; // should be accepted
+ }
} // end ns1_unimplemented
} // end ns test_lambda_is_cce
diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp
index e57a898f2f10..80ceb3768d9e 100644
--- a/test/SemaCXX/default-assignment-operator.cpp
+++ b/test/SemaCXX/default-assignment-operator.cpp
@@ -1,16 +1,34 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-class Base { // expected-error {{cannot define the implicit copy assignment operator for 'Base', because non-static reference member 'ref' cannot use copy assignment operator}} \
- // expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}}
- int &ref; // expected-note {{declared here}} \
- // expected-note{{reference member 'ref' will never be initialized}}
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+class Base { // expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}}
+#if __cplusplus <= 199711L
+// expected-error@-2 {{cannot define the implicit copy assignment operator for 'Base', because non-static reference member 'ref' cannot use copy assignment operator}}
+#endif
+
+ int &ref; // expected-note{{reference member 'ref' will never be initialized}}
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{declared here}}
+#else
+ // expected-note@-4 2 {{copy assignment operator of 'Base' is implicitly deleted because field 'ref' is of reference type 'int &'}}
+#endif
};
-class X : Base { // // expected-error {{cannot define the implicit copy assignment operator for 'X', because non-static const member 'cint' cannot use copy assignment operator}} \
-// expected-note{{assignment operator for 'Base' first required here}}
+class X : Base {
+#if __cplusplus <= 199711L
+// expected-note@-2 {{assignment operator for 'Base' first required here}}
+// expected-error@-3 {{cannot define the implicit copy assignment operator for 'X', because non-static const member 'cint' cannot use copy assignment operator}}
+#else
+// expected-note@-5 2 {{copy assignment operator of 'X' is implicitly deleted because base class 'Base' has a deleted copy assignment operator}}
+#endif
+
public:
X();
- const int cint; // expected-note {{declared here}}
+ const int cint;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{declared here}}
+#endif
};
struct Y : X {
@@ -28,8 +46,17 @@ Z z2;
// Test1
void f(X x, const X cx) {
- x = cx; // expected-note{{assignment operator for 'X' first required here}}
x = cx;
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{assignment operator for 'X' first required here}}
+#else
+ // expected-error@-4 {{object of type 'X' cannot be assigned because its copy assignment operator is implicitly deleted}}
+#endif
+
+ x = cx;
+#if __cplusplus >= 201103L
+ // expected-error@-2 {{object of type 'X' cannot be assigned because its copy assignment operator is implicitly deleted}}
+#endif
z1 = z2;
}
@@ -73,36 +100,62 @@ void i() {
// Test5
-class E1 { // expected-error{{cannot define the implicit copy assignment operator for 'E1', because non-static const member 'a' cannot use copy assignment operator}}
+class E1 {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{cannot define the implicit copy assignment operator for 'E1', because non-static const member 'a' cannot use copy assignment operator}}
+#endif
public:
- const int a; // expected-note{{declared here}}
- E1() : a(0) {}
+ const int a;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{declared here}}
+#else
+// expected-note@-4 {{copy assignment operator of 'E1' is implicitly deleted because field 'a' is of const-qualified type 'const int'}}
+#endif
+ E1() : a(0) {}
};
E1 e1, e2;
void j() {
- e1 = e2; // expected-note{{assignment operator for 'E1' first required here}}
+ e1 = e2;
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{assignment operator for 'E1' first required here}}
+#else
+ // expected-error@-4 {{object of type 'E1' cannot be assigned because its copy assignment operator is implicitly deleted}}
+#endif
}
namespace ProtectedCheck {
struct X {
protected:
- X &operator=(const X&); // expected-note{{declared protected here}}
+ X &operator=(const X&);
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{declared protected here}}
+#endif
};
struct Y : public X { };
void f(Y y) { y = y; }
- struct Z { // expected-error{{'operator=' is a protected member of 'ProtectedCheck::X'}}
+ struct Z {
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{'operator=' is a protected member of 'ProtectedCheck::X'}}
+#endif
X x;
+#if __cplusplus >= 201103L
+ // expected-note@-2 {{copy assignment operator of 'Z' is implicitly deleted because field 'x' has an inaccessible copy assignment operator}}
+#endif
};
- void f(Z z) { z = z; } // expected-note{{implicit copy assignment operator}}
-
+ void f(Z z) { z = z; }
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{implicit copy assignment operator}}
+#else
+ // expected-error@-4 {{object of type 'ProtectedCheck::Z' cannot be assigned because its copy assignment operator is implicitly deleted}}
+#endif
}
namespace MultiplePaths {
diff --git a/test/SemaCXX/default-constructor-initializers.cpp b/test/SemaCXX/default-constructor-initializers.cpp
index e783f4982605..25c7064d5984 100644
--- a/test/SemaCXX/default-constructor-initializers.cpp
+++ b/test/SemaCXX/default-constructor-initializers.cpp
@@ -1,26 +1,59 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct X1 { // has no implicit default constructor
X1(int);
};
-struct X2 : X1 { // expected-note 2 {{'X2' declared here}}
+struct X2 : X1 {
+#if __cplusplus <= 199711L
+// expected-note@-2 2 {{'X2' declared here}}
+#endif
+
X2(int);
};
-struct X3 : public X2 { // expected-error {{implicit default constructor for 'X3' must explicitly initialize the base class 'X2' which does not have a default constructor}}
+struct X3 : public X2 {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{implicit default constructor for 'X3' must explicitly initialize the base class 'X2' which does not have a default constructor}}
+#else
+// expected-note@-4 {{default constructor of 'X3' is implicitly deleted because base class 'X2' has no default constructor}}
+#endif
};
-X3 x3; // expected-note {{first required here}}
-
-struct X4 { // expected-error {{must explicitly initialize the member 'x2'}} \
- // expected-error {{must explicitly initialize the reference member 'rx2'}}
- X2 x2; // expected-note {{member is declared here}}
- X2 & rx2; // expected-note {{declared here}}
+X3 x3;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{first required here}}
+#else
+// expected-error@-4 {{call to implicitly-deleted default constructor of 'X3'}}
+#endif
+
+struct X4 {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{must explicitly initialize the member 'x2'}}
+// expected-error@-3 {{must explicitly initialize the reference member 'rx2'}}
+#endif
+
+ X2 x2;
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{member is declared here}}
+#else
+ // expected-note@-4 {{default constructor of 'X4' is implicitly deleted because field 'x2' has no default constructor}}
+#endif
+
+ X2 & rx2;
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{declared here}}
+#endif
};
-X4 x4; // expected-note {{first required here}}
-
+X4 x4;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{first required here}}
+#else
+// expected-error@-4 {{call to implicitly-deleted default constructor of 'X4'}}
+#endif
struct Y1 { // has no implicit default constructor
Y1(int);
@@ -43,15 +76,33 @@ Y4 y4;
// More tests
-struct Z1 { // expected-error {{must explicitly initialize the reference member 'z'}} \
- // expected-error {{must explicitly initialize the const member 'c1'}}
- int& z; // expected-note {{declared here}}
- const int c1; // expected-note {{declared here}}
+struct Z1 {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{must explicitly initialize the reference member 'z'}}
+// expected-error@-3 {{must explicitly initialize the const member 'c1'}}
+#endif
+
+ int& z;
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{declared here}}
+#else
+ // expected-note@-4 {{default constructor of 'Z1' is implicitly deleted because field 'z' of reference type 'int &' would not be initialized}}
+#endif
+
+ const int c1;
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{declared here}}
+#endif
volatile int v1;
};
// Test default initialization which *requires* a constructor call for non-POD.
-Z1 z1; // expected-note {{first required here}}
+Z1 z1;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{first required here}}
+#else
+// expected-error@-4 {{call to implicitly-deleted default constructor of 'Z1'}}
+#endif
// Ensure that value initialization doesn't use trivial implicit constructors.
namespace PR7948 {
diff --git a/test/SemaCXX/designated-initializers-base-class.cpp b/test/SemaCXX/designated-initializers-base-class.cpp
new file mode 100644
index 000000000000..9c2e61ea2a6a
--- /dev/null
+++ b/test/SemaCXX/designated-initializers-base-class.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -std=c++1z -fsyntax-only -verify -Winitializer-overrides
+// expected-no-diagnostics
+
+struct B {
+ int x;
+};
+
+struct D : B {
+ int y;
+};
+
+void test() { D d = {1, .y = 2}; }
diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp
index 36a8ac625ac3..1c59ccad6e14 100644
--- a/test/SemaCXX/dllimport.cpp
+++ b/test/SemaCXX/dllimport.cpp
@@ -396,20 +396,28 @@ template<typename T> void __declspec(dllimport) funcTmplDecl2();
template<typename T> __declspec(dllimport) void funcTmplDef() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
// Import inline function template.
-#ifdef GNU
-// expected-warning@+5{{'dllimport' attribute ignored on inline function}}
-// expected-warning@+5{{'dllimport' attribute ignored on inline function}}
-// expected-warning@+6{{'dllimport' attribute ignored on inline function}}
-// expected-warning@+9{{'inlineFuncTmplDef' redeclared inline; 'dllimport' attribute ignored}}
-#endif
-template<typename T> __declspec(dllimport) inline void inlineFuncTmpl1() {}
-template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {}
+#ifdef GNU // MinGW always ignores dllimport on inline functions.
-template<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl();
+template<typename T> __declspec(dllimport) inline void inlineFuncTmpl1() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+
+template<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}}
template<typename T> void inlineFuncTmplDecl() {}
template<typename T> __declspec(dllimport) void inlineFuncTmplDef();
-template<typename T> inline void inlineFuncTmplDef() {}
+template<typename T> inline void inlineFuncTmplDef() {} // expected-warning{{'inlineFuncTmplDef' redeclared inline; 'dllimport' attribute ignored}}
+
+#else // MSVC drops dllimport when the function template is redeclared without it. (It doesn't warn, but we do.)
+
+template<typename T> __declspec(dllimport) inline void inlineFuncTmpl1() {}
+template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {}
+
+template<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+template<typename T> void inlineFuncTmplDecl() {} // expected-warning{{'inlineFuncTmplDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+
+template<typename T> __declspec(dllimport) void inlineFuncTmplDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+template<typename T> inline void inlineFuncTmplDef() {} // expected-warning{{'inlineFuncTmplDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#endif
// Redeclarations
template<typename T> __declspec(dllimport) void funcTmplRedecl1();
@@ -436,7 +444,9 @@ struct FuncTmplFriend {
template<typename T> friend __declspec(dllimport) void funcTmplFriend3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
template<typename T> friend void funcTmplFriend4(); // expected-note{{previous declaration is here}}
#ifdef GNU
-// expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+// expected-warning@+4{{'dllimport' attribute ignored on inline function}}
+#else
+// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}}
#endif
template<typename T> friend __declspec(dllimport) inline void funcTmplFriend5();
};
@@ -444,6 +454,9 @@ template<typename T> __declspec(dllimport) void funcTmplFriend1();
template<typename T> void funcTmplFriend2(); // expected-warning{{'funcTmplFriend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
template<typename T> void funcTmplFriend3() {} // expected-warning{{'funcTmplFriend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
template<typename T> __declspec(dllimport) void funcTmplFriend4(); // expected-error{{redeclaration of 'funcTmplFriend4' cannot add 'dllimport' attribute}}
+#ifdef MS
+// expected-warning@+2{{'funcTmplFriend5' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#endif
template<typename T> inline void funcTmplFriend5() {}
// External linkage is required.
@@ -827,21 +840,28 @@ __declspec(dllimport) constexpr int MemberRedecl::ConstexprField; // expect
struct ImportMemberTmpl {
template<typename T> __declspec(dllimport) void normalDecl();
template<typename T> __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+#ifdef MS
+// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}}
+#endif
template<typename T> __declspec(dllimport) void normalInlineDef();
template<typename T> __declspec(dllimport) static void staticDecl();
template<typename T> __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+#ifdef MS
+// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}}
+#endif
template<typename T> __declspec(dllimport) static void staticInlineDef();
#ifdef GNU
- // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
- // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
- // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
- // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
-#endif
+ template<typename T> __declspec(dllimport) void normalInclass() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+ template<typename T> __declspec(dllimport) inline void normalInlineDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}}
+ template<typename T> __declspec(dllimport) static void staticInclass() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
+ template<typename T> __declspec(dllimport) static inline void staticInlineDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}}
+#else
template<typename T> __declspec(dllimport) void normalInclass() {}
- template<typename T> __declspec(dllimport) inline void normalInlineDecl();
+ template<typename T> __declspec(dllimport) inline void normalInlineDecl(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
template<typename T> __declspec(dllimport) static void staticInclass() {}
- template<typename T> __declspec(dllimport) static inline void staticInlineDecl();
+ template<typename T> __declspec(dllimport) static inline void staticInlineDecl(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+#endif
#if __has_feature(cxx_variable_templates)
template<typename T> __declspec(dllimport) static int StaticField;
@@ -856,16 +876,22 @@ struct ImportMemberTmpl {
};
template<typename T> void ImportMemberTmpl::normalDef() {} // expected-warning{{'ImportMemberTmpl::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
-template<typename T> void ImportMemberTmpl::normalInlineDecl() {}
template<typename T> void ImportMemberTmpl::staticDef() {} // expected-warning{{'ImportMemberTmpl::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#ifdef GNU // dllimport was ignored above
+template<typename T> void ImportMemberTmpl::normalInlineDecl() {}
template<typename T> void ImportMemberTmpl::staticInlineDecl() {}
+#else // dllimport dropped here
+template<typename T> void ImportMemberTmpl::normalInlineDecl() {} // expected-warning{{'ImportMemberTmpl::normalInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+template<typename T> void ImportMemberTmpl::staticInlineDecl() {} // expected-warning{{'ImportMemberTmpl::staticInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#endif
#ifdef GNU
-// expected-warning@+3{{ImportMemberTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}}
-// expected-warning@+3{{ImportMemberTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+template<typename T> inline void ImportMemberTmpl::normalInlineDef() {} // expected-warning{{ImportMemberTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+template<typename T> inline void ImportMemberTmpl::staticInlineDef() {} // expected-warning{{ImportMemberTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#else
+template<typename T> inline void ImportMemberTmpl::normalInlineDef() {} // expected-warning{{ImportMemberTmpl::normalInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+template<typename T> inline void ImportMemberTmpl::staticInlineDef() {} // expected-warning{{ImportMemberTmpl::staticInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
#endif
-template<typename T> inline void ImportMemberTmpl::normalInlineDef() {}
-template<typename T> inline void ImportMemberTmpl::staticInlineDef() {}
#if __has_feature(cxx_variable_templates)
template<typename T> int ImportMemberTmpl::StaticFieldDef; // expected-error{{definition of dllimport static field not allowed}}
@@ -1240,20 +1266,32 @@ template<typename T>
struct ImportClsTmplMemTmpl {
template<typename U> __declspec(dllimport) void normalDecl();
template<typename U> __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+#ifdef MS
+// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}}
+#endif
template<typename U> __declspec(dllimport) void normalInlineDef();
template<typename U> __declspec(dllimport) static void staticDecl();
template<typename U> __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}}
+#ifdef MS
+// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}}
+#endif
template<typename U> __declspec(dllimport) static void staticInlineDef();
#ifdef GNU
// expected-warning@+5{{'dllimport' attribute ignored on inline function}}
- // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
- // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
- // expected-warning@+5{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+8{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+8{{'dllimport' attribute ignored on inline function}}
+ // expected-warning@+11{{'dllimport' attribute ignored on inline function}}
#endif
template<typename U> __declspec(dllimport) void normalInclass() {}
+#ifdef MS
+// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}}
+#endif
template<typename U> __declspec(dllimport) inline void normalInlineDecl();
template<typename U> __declspec(dllimport) static void staticInclass() {}
+#ifdef MS
+// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}}
+#endif
template<typename U> __declspec(dllimport) static inline void staticInlineDecl();
#if __has_feature(cxx_variable_templates)
@@ -1269,16 +1307,22 @@ struct ImportClsTmplMemTmpl {
};
template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
-template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalInlineDecl() {}
template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::staticDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#ifdef GNU
+template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalInlineDecl() {}
template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::staticInlineDecl() {}
+#else
+template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalInlineDecl() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::staticInlineDecl() {} // expected-warning{{'ImportClsTmplMemTmpl::staticInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+#endif
#ifdef GNU
-// expected-warning@+3{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}}
-// expected-warning@+3{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::normalInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::staticInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}}
+#else
+template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::normalInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
+template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::staticInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
#endif
-template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::normalInlineDef() {}
-template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::staticInlineDef() {}
#if __has_feature(cxx_variable_templates)
template<typename T> template<typename U> int ImportClsTmplMemTmpl<T>::StaticFieldDef; // expected-warning{{definition of dllimport static field}}
diff --git a/test/SemaCXX/enable_if.cpp b/test/SemaCXX/enable_if.cpp
index eababc34d370..9a06d3866110 100644
--- a/test/SemaCXX/enable_if.cpp
+++ b/test/SemaCXX/enable_if.cpp
@@ -246,11 +246,11 @@ namespace FnPtrs {
int noOvlNoCandidate(int m) __attribute__((enable_if(false, "")));
void test8() {
- int (*p)(int) = noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}}
- int (*p2)(int) = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}}
+ int (*p)(int) = noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' because it has one or more non-tautological enable_if conditions}}
+ int (*p2)(int) = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' because it has one or more non-tautological enable_if conditions}}
int (*a)(int);
- a = noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}}
- a = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}}
+ a = noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' because it has one or more non-tautological enable_if conditions}}
+ a = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' because it has one or more non-tautological enable_if conditions}}
}
}
@@ -472,3 +472,30 @@ namespace instantiate_constexpr_in_enable_if {
};
void g() { X<int>().f(); }
}
+
+namespace PR31934 {
+int foo(int a) __attribute__((enable_if(a, "")));
+int runFn(int (&)(int));
+
+void run() {
+ {
+ int (&bar)(int) = foo; // expected-error{{cannot take address of function 'foo'}}
+ int baz = runFn(foo); // expected-error{{cannot take address of function 'foo'}}
+ }
+
+ {
+ int (&bar)(int) = (foo); // expected-error{{cannot take address of function 'foo'}}
+ int baz = runFn((foo)); // expected-error{{cannot take address of function 'foo'}}
+ }
+
+ {
+ int (&bar)(int) = static_cast<int (&)(int)>(foo); // expected-error{{cannot take address of function 'foo'}}
+ int baz = runFn(static_cast<int (&)(int)>(foo)); // expected-error{{cannot take address of function 'foo'}}
+ }
+
+ {
+ int (&bar)(int) = static_cast<int (&)(int)>((foo)); // expected-error{{cannot take address of function 'foo'}}
+ int baz = runFn(static_cast<int (&)(int)>((foo))); // expected-error{{cannot take address of function 'foo'}}
+ }
+}
+}
diff --git a/test/SemaCXX/enum-attr.cpp b/test/SemaCXX/enum-attr.cpp
new file mode 100644
index 000000000000..7726aff4830a
--- /dev/null
+++ b/test/SemaCXX/enum-attr.cpp
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wassign-enum -Wswitch-enum -Wcovered-switch-default -std=c++11 %s
+
+enum Enum {
+ A0 = 1, A1 = 10
+};
+
+enum __attribute__((enum_extensibility(closed))) EnumClosed {
+ B0 = 1, B1 = 10
+};
+
+enum [[clang::enum_extensibility(open)]] EnumOpen {
+ C0 = 1, C1 = 10
+};
+
+enum __attribute__((flag_enum)) EnumFlag {
+ D0 = 1, D1 = 8
+};
+
+enum __attribute__((flag_enum,enum_extensibility(closed))) EnumFlagClosed {
+ E0 = 1, E1 = 8
+};
+
+enum __attribute__((flag_enum,enum_extensibility(open))) EnumFlagOpen {
+ F0 = 1, F1 = 8
+};
+
+void test() {
+ enum Enum t0;
+
+ switch (t0) { // expected-warning{{enumeration value 'A1' not handled in switch}}
+ case A0: break;
+ case 16: break; // expected-warning{{case value not in enumerated type}}
+ }
+
+ switch (t0) {
+ case A0: break;
+ case A1: break;
+ default: break; // expected-warning{{default label in switch which covers all enumeration}}
+ }
+
+ enum EnumClosed t1;
+
+ switch (t1) { // expected-warning{{enumeration value 'B1' not handled in switch}}
+ case B0: break;
+ case 16: break; // expected-warning{{case value not in enumerated type}}
+ }
+
+ switch (t1) {
+ case B0: break;
+ case B1: break;
+ default: break; // expected-warning{{default label in switch which covers all enumeration}}
+ }
+
+ enum EnumOpen t2;
+
+ switch (t2) { // expected-warning{{enumeration value 'C1' not handled in switch}}
+ case C0: break;
+ case 16: break;
+ }
+
+ switch (t2) {
+ case C0: break;
+ case C1: break;
+ default: break;
+ }
+
+ enum EnumFlag t3;
+
+ switch (t3) { // expected-warning{{enumeration value 'D1' not handled in switch}}
+ case D0: break;
+ case 9: break;
+ case 16: break; // expected-warning{{case value not in enumerated type}}
+ }
+
+ switch (t3) {
+ case D0: break;
+ case D1: break;
+ default: break;
+ }
+
+ enum EnumFlagClosed t4;
+
+ switch (t4) { // expected-warning{{enumeration value 'E1' not handled in switch}}
+ case E0: break;
+ case 9: break;
+ case 16: break; // expected-warning{{case value not in enumerated type}}
+ }
+
+ switch (t4) {
+ case E0: break;
+ case E1: break;
+ default: break;
+ }
+
+ enum EnumFlagOpen t5;
+
+ switch (t5) { // expected-warning{{enumeration value 'F1' not handled in switch}}
+ case F0: break;
+ case 9: break;
+ case 16: break;
+ }
+
+ switch (t5) {
+ case F0: break;
+ case F1: break;
+ default: break;
+ }
+}
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index 142edd3893aa..3114bca9347d 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -307,5 +307,5 @@ namespace test11 {
typedef E E2;
E2 f1() { return E::a; }
- bool f() { return !f1(); } // expected-error {{invalid argument type 'E2' (aka 'test11::E') to unary expression}}
+ bool f() { return !f1(); } // expected-error {{invalid argument type 'test11::E2' (aka 'test11::E') to unary expression}}
}
diff --git a/test/SemaCXX/format-strings.cpp b/test/SemaCXX/format-strings.cpp
index b7ef1d709f21..a0dcf01910bb 100644
--- a/test/SemaCXX/format-strings.cpp
+++ b/test/SemaCXX/format-strings.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks -std=c++11 %s
#include <stdarg.h>
@@ -9,9 +11,13 @@ extern int vprintf(const char *restrict, va_list);
}
void f(char **sp, float *fp) {
- scanf("%as", sp); // expected-warning{{'a' length modifier is not supported by ISO C}}
+ scanf("%as", sp);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{'a' length modifier is not supported by ISO C}}
+#else
+ // expected-warning@-4 {{format specifies type 'float *' but the argument has type 'char **'}}
+#endif
- // TODO: Warn that the 'a' conversion specifier is a C++11 feature.
printf("%a", 1.0);
scanf("%afoobar", fp);
}
@@ -46,11 +52,19 @@ void h(int *i) {
// Test handling __null for format string literal checking.
extern "C" {
int test_null_format(const char *format, ...) __attribute__((__format__ (__printf__, 1, 2)));
+#if __cplusplus >= 201103L
+ // expected-note@-2 {{candidate function not viable: no known conversion from 'bool' to 'const char *' for 1st argument}}
+#endif
}
void rdar8269537(const char *f)
{
- test_null_format(false); // expected-warning {{null from a constant boolean}}
+ test_null_format(false);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{null from a constant boolean}}
+#else
+ // expected-error@-4 {{no matching function for call to 'test_null_format'}}
+#endif
test_null_format(0); // no-warning
test_null_format(__null); // no-warning
test_null_format(f); // expected-warning {{not a string literal}}
diff --git a/test/SemaCXX/friend3.cpp b/test/SemaCXX/friend3.cpp
new file mode 100644
index 000000000000..8b83ca78d403
--- /dev/null
+++ b/test/SemaCXX/friend3.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -S -triple %itanium_abi_triple -std=c++11 -emit-llvm %s -o - | FileCheck %s
+
+namespace pr8852 {
+void foo();
+struct S {
+ friend void foo() {}
+};
+
+void main() {
+ foo();
+}
+// CHECK: define {{.*}} @_ZN6pr88523fooEv
+}
+
+namespace pr9518 {
+template<typename T>
+struct provide {
+ friend T f() { return T(); }
+};
+
+void g() {
+ void f();
+ provide<void> p;
+ f();
+}
+// CHECK: define {{.*}} @_ZN6pr95181fEv
+}
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
index 39c6b1fc1320..9e01ccb6b336 100644
--- a/test/SemaCXX/i-c-e-cxx.cpp
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -std=gnu++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -std=gnu++11 %s
// C++-specific tests for integral constant expressions.
@@ -16,9 +18,21 @@ void f() {
}
int a() {
- const int t=t; // expected-note {{declared here}} expected-note {{read of object outside its lifetime}}
- switch(1) { // expected-warning {{no case matching constant switch condition '1'}}
- case t:; // expected-error {{not an integral constant expression}} expected-note {{initializer of 't' is not a constant expression}}
+ const int t=t; // expected-note {{declared here}}
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{read of object outside its lifetime}}
+#endif
+
+ switch(1) {
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{no case matching constant switch condition '1'}}
+#endif
+ case t:; // expected-note {{initializer of 't' is not a constant expression}}
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{not an integral constant expression}}
+#else
+ // expected-error@-4 {{case value is not a constant expression}}
+#endif
}
}
@@ -48,7 +62,10 @@ void pr6373(const unsigned x = 0) {
namespace rdar9204520 {
struct A {
- static const int B = int(0.75 * 1000 * 1000); // expected-warning {{not a constant expression; folding it to a constant is a GNU extension}}
+ static const int B = int(0.75 * 1000 * 1000);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{not a constant expression; folding it to a constant is a GNU extension}}
+#endif
};
int foo() { return A::B; }
@@ -59,10 +76,24 @@ const int x = 10;
int* y = reinterpret_cast<const char&>(x); // expected-error {{cannot initialize}}
// This isn't an integral constant expression, but make sure it folds anyway.
-struct PR8836 { char _; long long a; }; // expected-warning {{long long}}
-int PR8836test[(__typeof(sizeof(int)))&reinterpret_cast<const volatile char&>((((PR8836*)0)->a))]; // expected-warning {{folded to constant array as an extension}} expected-note {{cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
+struct PR8836 { char _; long long a; };
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{'long long' is a C++11 extension}}
+#endif
+
+int PR8836test[(__typeof(sizeof(int)))&reinterpret_cast<const volatile char&>((((PR8836*)0)->a))];
+// expected-warning@-1 {{folded to constant array as an extension}}
+// expected-note@-2 {{cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
+
+const int nonconst = 1.0;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{declared here}}
+#endif
+int arr[nonconst];
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{folded to constant array as an extension}}
+// expected-note@-3 {{initializer of 'nonconst' is not a constant expression}}
+#endif
-const int nonconst = 1.0; // expected-note {{declared here}}
-int arr[nonconst]; // expected-warning {{folded to constant array as an extension}} expected-note {{initializer of 'nonconst' is not a constant expression}}
const int castfloat = static_cast<int>(1.0);
int arr2[castfloat]; // ok
diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp
index fc86d1810ba5..f400c222de83 100644
--- a/test/SemaCXX/implicit-exception-spec.cpp
+++ b/test/SemaCXX/implicit-exception-spec.cpp
@@ -92,3 +92,61 @@ namespace ImplicitDtorExceptionSpec {
} e;
};
}
+
+struct nothrow_t {} nothrow;
+void *operator new(decltype(sizeof(0)), nothrow_t) noexcept;
+
+namespace PotentiallyConstructed {
+ template<bool NE> struct A {
+ A() noexcept(NE);
+ A(const A&) noexcept(NE);
+ A(A&&) noexcept(NE);
+ A &operator=(const A&) noexcept(NE);
+ A &operator=(A&&) noexcept(NE);
+ ~A() noexcept(NE);
+ };
+
+ template<bool NE> struct B : virtual A<NE> {};
+
+ template<bool NE> struct C : virtual A<NE> {
+ virtual void f() = 0; // expected-note 2{{unimplemented}}
+ };
+
+ template<bool NE> struct D final : C<NE> {
+ void f();
+ };
+
+ template<typename T, bool A, bool B, bool C, bool D, bool E, bool F> void check() {
+ T *p = nullptr;
+ T &a = *p;
+ static_assert(noexcept(a = a) == D, "");
+ static_assert(noexcept(a = static_cast<T&&>(a)) == E, "");
+ static_assert(noexcept(delete &a) == F, ""); // expected-warning 2{{abstract}}
+
+ // These are last because the first failure here causes instantiation to bail out.
+ static_assert(noexcept(new (nothrow) T()) == A, ""); // expected-error 2{{abstract}}
+ static_assert(noexcept(new (nothrow) T(a)) == B, "");
+ static_assert(noexcept(new (nothrow) T(static_cast<T&&>(a))) == C, "");
+ }
+
+ template void check<A<false>, 0, 0, 0, 0, 0, 0>();
+ template void check<A<true >, 1, 1, 1, 1, 1, 1>();
+ template void check<B<false>, 0, 0, 0, 0, 0, 0>();
+ template void check<B<true >, 1, 1, 1, 1, 1, 1>();
+ template void check<C<false>, 1, 1, 1, 0, 0, 0>(); // expected-note {{instantiation}}
+ template void check<C<true >, 1, 1, 1, 1, 1, 1>(); // expected-note {{instantiation}}
+ template void check<D<false>, 0, 0, 0, 0, 0, 0>();
+ template void check<D<true >, 1, 1, 1, 1, 1, 1>();
+
+ // ... the above trick doesn't work for this case...
+ struct Cfalse : virtual A<false> {
+ virtual void f() = 0;
+
+ Cfalse() noexcept;
+ Cfalse(const Cfalse&) noexcept;
+ Cfalse(Cfalse&&) noexcept;
+ };
+ Cfalse::Cfalse() noexcept = default;
+ Cfalse::Cfalse(const Cfalse&) noexcept = default;
+ Cfalse::Cfalse(Cfalse&&) noexcept = default;
+}
diff --git a/test/SemaCXX/implicit-member-functions.cpp b/test/SemaCXX/implicit-member-functions.cpp
index de679fe14a06..1554b1af5d59 100644
--- a/test/SemaCXX/implicit-member-functions.cpp
+++ b/test/SemaCXX/implicit-member-functions.cpp
@@ -66,7 +66,8 @@ namespace Recursion {
A(const T &);
// expected-note@-1 {{in instantiation of default argument}}
};
- struct B { // expected-note {{candidate constructor (the implicit move }}
+ struct B { // expected-note {{while declaring the implicit copy constructor for 'B'}}
+ // expected-note@-1 {{candidate constructor (the implicit move }}
B(); // expected-note {{candidate constructor not viable}}
A a;
};
diff --git a/test/SemaCXX/implicit-virtual-member-functions.cpp b/test/SemaCXX/implicit-virtual-member-functions.cpp
index f88a55c3d5b4..319cad75864e 100644
--- a/test/SemaCXX/implicit-virtual-member-functions.cpp
+++ b/test/SemaCXX/implicit-virtual-member-functions.cpp
@@ -1,33 +1,87 @@
// RUN: %clang_cc1 -fsyntax-only -triple %itanium_abi_triple -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple %itanium_abi_triple -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -triple %itanium_abi_triple -verify -std=c++11 %s
// RUN: %clang_cc1 -fsyntax-only -triple %ms_abi_triple -DMSABI -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple %ms_abi_triple -DMSABI -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -triple %ms_abi_triple -DMSABI -verify -std=c++11 %s
+
struct A {
virtual ~A();
+#if __cplusplus >= 201103L
+// expected-note@-2 3 {{overridden virtual function is here}}
+#endif
};
-struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}}
+struct B : A {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{no suitable member 'operator delete' in 'B'}}
+#else
+// expected-error@-4 {{deleted function '~B' cannot override a non-deleted function}}
+// expected-note@-5 {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+#ifdef MSABI
+// expected-note@-7 {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+#endif
+#endif
virtual void f();
- void operator delete (void *, int); // expected-note {{'operator delete' declared here}}
+ void operator delete (void *, int);
+#if __cplusplus <= 199711L
+// expected-note@-2 {{'operator delete' declared here}}
+#endif
};
#ifdef MSABI
-B b; // expected-note {{implicit destructor for 'B' first required here}}
+B b;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'B' first required here}}
+#else
+// expected-error@-4 {{attempt to use a deleted function}}
+#endif
+
#else
-void B::f() { // expected-note {{implicit destructor for 'B' first required here}}
+void B::f() {
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'B' first required here}}
+#endif
}
#endif
-struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
+struct C : A {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{no suitable member 'operator delete' in 'C'}}
+#else
+// expected-error@-4 {{deleted function '~C' cannot override a non-deleted function}}
+// expected-note@-5 {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+#endif
+
C();
- void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
+ void operator delete(void *, int);
+#if __cplusplus <= 199711L
+// expected-note@-2 {{'operator delete' declared here}}
+#endif
};
-C::C() { } // expected-note {{implicit destructor for 'C' first required here}}
+C::C() { }
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'C' first required here}}
+#endif
-struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}}
- void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
+struct D : A {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{no suitable member 'operator delete' in 'D'}}
+#else
+// expected-error@-4 {{deleted function '~D' cannot override a non-deleted function}}
+// expected-note@-5 {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+#endif
+ void operator delete(void *, int);
+#if __cplusplus <= 199711L
+// expected-note@-2 {{'operator delete' declared here}}
+#endif
};
void f() {
- new D; // expected-note {{implicit destructor for 'D' first required here}}
+ new D;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'D' first required here}}
+#endif
}
diff --git a/test/SemaCXX/libstdcxx_pair_swap_hack.cpp b/test/SemaCXX/libstdcxx_pair_swap_hack.cpp
index 9f9c71a50ce1..dff599b6d5b6 100644
--- a/test/SemaCXX/libstdcxx_pair_swap_hack.cpp
+++ b/test/SemaCXX/libstdcxx_pair_swap_hack.cpp
@@ -88,7 +88,7 @@ namespace sad {
CLASS<int, int> pi;
- static_assert(!noexcept(pi.swap(pi)), ""); // expected-note {{in instantiation of}}
+ static_assert(!noexcept(pi.swap(pi)), ""); // expected-note 2{{in instantiation of exception specification for 'swap'}}
}
#endif
diff --git a/test/SemaCXX/make_integer_seq.cpp b/test/SemaCXX/make_integer_seq.cpp
index a9b8d2b23cb5..8f72ce15eef4 100644
--- a/test/SemaCXX/make_integer_seq.cpp
+++ b/test/SemaCXX/make_integer_seq.cpp
@@ -43,7 +43,7 @@ enum Color : int { Red,
Blue };
using illformed1 = ErrorSeq<Color, Blue>; // expected-note{{in instantiation}}
-using illformed2 = ErrorSeq<int, -5>;
+using illformed2 = ErrorSeq<int, -5>; // expected-note{{in instantiation}}
template <typename T, T N> void f() {}
__make_integer_seq<f, int, 0> x; // expected-error{{template template parameter must be a class template or type alias template}}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index f445725c7429..6ae45ff63332 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -310,7 +310,7 @@ namespace N {
}
namespace TypedefNamespace { typedef int F; };
-TypedefNamespace::F::NonexistentName BadNNSWithCXXScopeSpec; // expected-error {{'F' (aka 'int') is not a class, namespace, or enumeration}}
+TypedefNamespace::F::NonexistentName BadNNSWithCXXScopeSpec; // expected-error {{'TypedefNamespace::F' (aka 'int') is not a class, namespace, or enumeration}}
namespace PR18587 {
@@ -449,7 +449,7 @@ namespace A {
class B {
typedef C D; // expected-error{{unknown type name 'C'}}
A::D::F;
- // expected-error@-1{{'D' (aka 'int') is not a class, namespace, or enumeration}}
+ // expected-error@-1{{'PR30619::A::B::D' (aka 'int') is not a class, namespace, or enumeration}}
};
}
}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index e96603d69e10..cb0d030d99c2 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -1,7 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -Wno-new-returns-null
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++98
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11
#include <stddef.h>
+#if __cplusplus >= 201103L
+// expected-note@+2 {{candidate constructor (the implicit move constructor) not viable}}
+#endif
struct S // expected-note {{candidate}}
{
S(int, int, double); // expected-note {{candidate}}
@@ -72,7 +77,13 @@ void bad_news(int *ip)
(void)new; // expected-error {{expected a type}}
(void)new 4; // expected-error {{expected a type}}
(void)new () int; // expected-error {{expected expression}}
- (void)new int[1.1]; // expected-error {{array size expression must have integral or enumeration type, not 'double'}}
+ (void)new int[1.1];
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{array size expression must have integral or enumeration type, not 'double'}}
+#else
+ // expected-error@-4 {{array size expression must have integral or unscoped enumeration type, not 'double'}}
+#endif
+
(void)new int[1][i]; // expected-error {{only the first dimension}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
(void)new (int[1][i]); // expected-error {{only the first dimension}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
(void)new (int[i]); // expected-warning {{when type is in parentheses}}
@@ -85,7 +96,13 @@ void bad_news(int *ip)
// Undefined, but clang should reject it directly.
(void)new int[-1]; // expected-error {{array size is negative}}
(void)new int[2000000000]; // expected-error {{array is too large}}
- (void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumeration type, not 'S'}}
+ (void)new int[*(S*)0];
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{array size expression must have integral or enumeration type, not 'S'}}
+#else
+ // expected-error@-4 {{array size expression must have integral or unscoped enumeration type, not 'S'}}
+#endif
+
(void)::S::new int; // expected-error {{expected unqualified-id}}
(void)new (0, 0) int; // expected-error {{no matching function for call to 'operator new'}}
(void)new (0L) int; // expected-error {{call to 'operator new' is ambiguous}}
@@ -109,7 +126,12 @@ void good_deletes()
void bad_deletes()
{
delete 0; // expected-error {{cannot delete expression of type 'int'}}
- delete [0] (int*)0; // expected-error {{expected expression}}
+ delete [0] (int*)0;
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{expected expression}}
+#else
+ // expected-error@-4 {{expected variable name or 'this' in lambda capture list}}
+#endif
delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}}
delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
::S::delete (int*)0; // expected-error {{expected unqualified-id}}
@@ -209,14 +231,31 @@ void f(X9 *x9) {
struct X10 {
virtual ~X10();
+#if __cplusplus >= 201103L
+ // expected-note@-2 {{overridden virtual function is here}}
+#endif
};
-struct X11 : X10 { // expected-error {{no suitable member 'operator delete' in 'X11'}}
- void operator delete(void*, int); // expected-note {{'operator delete' declared here}}
+struct X11 : X10 {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{no suitable member 'operator delete' in 'X11'}}
+#else
+// expected-error@-4 {{deleted function '~X11' cannot override a non-deleted function}}
+// expected-note@-5 2 {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+#endif
+ void operator delete(void*, int);
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{'operator delete' declared here}}
+#endif
};
void f() {
- X11 x11; // expected-note {{implicit destructor for 'X11' first required here}}
+ X11 x11;
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{implicit destructor for 'X11' first required here}}
+#else
+ // expected-error@-4 {{attempt to use a deleted function}}
+#endif
}
struct X12 {
@@ -398,10 +437,24 @@ namespace PR7702 {
}
namespace ArrayNewNeedsDtor {
- struct A { A(); private: ~A(); }; // expected-note {{declared private here}}
- struct B { B(); A a; }; // expected-error {{field of type 'ArrayNewNeedsDtor::A' has private destructor}}
+ struct A { A(); private: ~A(); };
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{declared private here}}
+#endif
+ struct B { B(); A a; };
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{field of type 'ArrayNewNeedsDtor::A' has private destructor}}
+#else
+ // expected-note@-4 {{destructor of 'B' is implicitly deleted because field 'a' has an inaccessible destructor}}
+#endif
+
B *test9() {
- return new B[5]; // expected-note {{implicit destructor for 'ArrayNewNeedsDtor::B' first required here}}
+ return new B[5];
+#if __cplusplus <= 199711L
+ // expected-note@-2 {{implicit destructor for 'ArrayNewNeedsDtor::B' first required here}}
+#else
+ // expected-error@-4 {{attempt to use a deleted function}}
+#endif
}
}
diff --git a/test/SemaCXX/no-wchar.cpp b/test/SemaCXX/no-wchar.cpp
index b6dcddf1f428..040b46cdf5e5 100644
--- a/test/SemaCXX/no-wchar.cpp
+++ b/test/SemaCXX/no-wchar.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -fno-wchar -verify %s
+// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -fno-wchar -verify -std=c++98 %s
+// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -fno-wchar -verify -std=c++11 %s
wchar_t x; // expected-error {{unknown type name 'wchar_t'}}
typedef unsigned short wchar_t;
@@ -9,7 +11,11 @@ void bar() {
}
void foo1(wchar_t * t = L"");
-// expected-warning@-1 {{conversion from string literal to 'wchar_t *' (aka 'unsigned short *') is deprecated}}
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{conversion from string literal to 'wchar_t *' (aka 'unsigned short *') is deprecated}}
+#else
+// expected-warning@-4 {{ISO C++11 does not allow conversion from string literal to 'wchar_t *' (aka 'unsigned short *')}}
+#endif
short *a = L"";
// expected-error@-1 {{cannot initialize a variable of type 'short *' with an lvalue of type 'const unsigned short [1]'}}
diff --git a/test/SemaCXX/printf-cstr.cpp b/test/SemaCXX/printf-cstr.cpp
index a7eeb06b9c0e..32f4d98a49c6 100644
--- a/test/SemaCXX/printf-cstr.cpp
+++ b/test/SemaCXX/printf-cstr.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -Wformat -verify %s -Wno-error=non-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -Wformat -verify -std=c++98 %s -Wno-error=non-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -Wformat -verify -std=c++11 %s -Wno-error=non-pod-varargs
#include <stdarg.h>
@@ -31,12 +33,39 @@ void pod_test() {
int n = 10;
printf("%d: %s\n", n, hcs.c_str());
- printf("%d: %s\n", n, hcs); // expected-warning{{cannot pass non-POD object of type 'HasCStr' to variadic function; expected type from format string was 'char *'}} expected-note{{did you mean to call the c_str() method?}}
- printf("%d: %s\n", n, hncs); // expected-warning{{cannot pass non-POD object of type 'HasNoCStr' to variadic function; expected type from format string was 'char *'}}
- sprintf(str, "%d: %s", n, hcs); // expected-warning{{cannot pass non-POD object of type 'HasCStr' to variadic function; expected type from format string was 'char *'}} expected-note{{did you mean to call the c_str() method?}}
+ printf("%d: %s\n", n, hcs);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{cannot pass non-POD object of type 'HasCStr' to variadic function; expected type from format string was 'char *'}}
+ // expected-note@-3 {{did you mean to call the c_str() method?}}
+#else
+ // expected-warning@-5 {{format specifies type 'char *' but the argument has type 'HasCStr'}}
+#endif
- printf(formatString, hcs, hncs); // expected-warning{{cannot pass object of non-POD type 'HasCStr' through variadic function}} expected-warning{{cannot pass object of non-POD type 'HasNoCStr' through variadic function}}
- printf(extstr, hcs, n); // expected-warning{{cannot pass object of non-POD type 'HasCStr' through variadic function}}
+ printf("%d: %s\n", n, hncs);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{cannot pass non-POD object of type 'HasNoCStr' to variadic function; expected type from format string was 'char *'}}
+#else
+ // expected-warning@-4 {{format specifies type 'char *' but the argument has type 'HasNoCStr'}}
+#endif
+
+ sprintf(str, "%d: %s", n, hcs);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{cannot pass non-POD object of type 'HasCStr' to variadic function; expected type from format string was 'char *'}}
+ // expected-note@-3 {{did you mean to call the c_str() method?}}
+#else
+ // expected-warning@-5 {{format specifies type 'char *' but the argument has type 'HasCStr'}}
+#endif
+
+ printf(formatString, hcs, hncs);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{cannot pass object of non-POD type 'HasCStr' through variadic function}}
+ // expected-warning@-3 {{cannot pass object of non-POD type 'HasNoCStr' through variadic function}}
+#endif
+
+ printf(extstr, hcs, n);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{cannot pass object of non-POD type 'HasCStr' through variadic function}}
+#endif
}
struct Printf {
@@ -49,5 +78,11 @@ void constructor_test() {
const char str[] = "test";
HasCStr hcs(str);
Printf p("%s %d %s", str, 10, 10); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}}
- Printf q("%s %d", hcs, 10); // expected-warning {{cannot pass non-POD object of type 'HasCStr' to variadic constructor; expected type from format string was 'char *'}} expected-note{{did you mean to call the c_str() method?}}
+ Printf q("%s %d", hcs, 10);
+#if __cplusplus <= 199711L
+ // expected-warning@-2 {{cannot pass non-POD object of type 'HasCStr' to variadic constructor; expected type from format string was 'char *'}}
+ // expected-note@-3 {{did you mean to call the c_str() method?}}
+#else
+ // expected-warning@-5 {{format specifies type 'char *' but the argument has type 'HasCStr'}}
+#endif
}
diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
index 45f1eafba10a..08938bf34a79 100644
--- a/test/SemaCXX/pseudo-destructors.cpp
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -89,3 +89,26 @@ template<typename T> using Id = T;
void AliasTemplate(int *p) {
p->~Id<int>();
}
+
+namespace dotPointerAccess {
+struct Base {
+ virtual ~Base() {}
+};
+
+struct Derived : Base {
+ ~Derived() {}
+};
+
+void test() {
+ Derived d;
+ static_cast<Base *>(&d).~Base(); // expected-error {{member reference type 'dotPointerAccess::Base *' is a pointer; did you mean to use '->'}}
+ d->~Derived(); // expected-error {{member reference type 'dotPointerAccess::Derived' is not a pointer; did you mean to use '.'}}
+}
+
+typedef Derived *Foo;
+
+void test2(Foo d) {
+ d.~Foo(); // This is ok
+ d.~Derived(); // expected-error {{member reference type 'dotPointerAccess::Foo' (aka 'dotPointerAccess::Derived *') is a pointer; did you mean to use '->'}}
+}
+}
diff --git a/test/SemaCXX/ptrtomember.cpp b/test/SemaCXX/ptrtomember.cpp
index aee535e5593b..d4a4507d02a5 100644
--- a/test/SemaCXX/ptrtomember.cpp
+++ b/test/SemaCXX/ptrtomember.cpp
@@ -13,9 +13,13 @@ int foo(int S::* ps, S *s)
struct S2 {
int bitfield : 1;
+ struct {
+ int anon_bitfield : 1;
+ };
};
int S2::*pf = &S2::bitfield; // expected-error {{address of bit-field requested}}
+int S2::*anon_pf = &S2::anon_bitfield; // expected-error {{address of bit-field requested}}
struct S3 {
void m();
diff --git a/test/SemaCXX/suppress.cpp b/test/SemaCXX/suppress.cpp
new file mode 100644
index 000000000000..d88ae0bbca00
--- /dev/null
+++ b/test/SemaCXX/suppress.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify
+
+[[gsl::suppress("globally")]];
+
+namespace N {
+ [[gsl::suppress("in-a-namespace")]];
+}
+
+[[gsl::suppress("readability-identifier-naming")]]
+void f_() {
+ int *p;
+ [[gsl::suppress("type", "bounds")]] {
+ p = reinterpret_cast<int *>(7);
+ }
+
+ [[gsl::suppress]] int x; // expected-error {{'suppress' attribute takes at least 1 argument}}
+ [[gsl::suppress()]] int y; // expected-error {{'suppress' attribute takes at least 1 argument}}
+ int [[gsl::suppress("r")]] z; // expected-error {{'suppress' attribute cannot be applied to types}}
+ [[gsl::suppress(f_)]] float f; // expected-error {{'suppress' attribute requires a string}}
+}
+
+union [[gsl::suppress("type.1")]] U {
+ int i;
+ float f;
+};
diff --git a/test/SemaCXX/template-multiple-attr-propagation.cpp b/test/SemaCXX/template-multiple-attr-propagation.cpp
new file mode 100644
index 000000000000..8e7f4570bad4
--- /dev/null
+++ b/test/SemaCXX/template-multiple-attr-propagation.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 %s -Wthread-safety-analysis -verify -fexceptions
+// expected-no-diagnostics
+
+class Mutex {
+public:
+ void Lock() __attribute__((exclusive_lock_function()));
+ void Unlock() __attribute__((unlock_function()));
+};
+
+class A {
+public:
+ Mutex mu1, mu2;
+
+ void foo() __attribute__((exclusive_locks_required(mu1))) __attribute__((exclusive_locks_required(mu2))) {}
+
+ template <class T>
+ void bar() __attribute__((exclusive_locks_required(mu1))) __attribute__((exclusive_locks_required(mu2))) {
+ foo();
+ }
+};
+
+void f() {
+ A a;
+ a.mu1.Lock();
+ a.mu2.Lock();
+ a.bar<int>();
+ a.mu2.Unlock();
+ a.mu1.Unlock();
+}
diff --git a/test/Sema/template-specialization.cpp b/test/SemaCXX/template-specialization.cpp
index ae7bc332fcce..ae7bc332fcce 100644
--- a/test/Sema/template-specialization.cpp
+++ b/test/SemaCXX/template-specialization.cpp
diff --git a/test/SemaCXX/type-convert-construct.cpp b/test/SemaCXX/type-convert-construct.cpp
index 7ae83638adb5..98e960727be2 100644
--- a/test/SemaCXX/type-convert-construct.cpp
+++ b/test/SemaCXX/type-convert-construct.cpp
@@ -8,7 +8,15 @@ void f() {
typedef int arr[];
int v3 = arr(); // expected-error {{array types cannot be value-initialized}}
typedef void fn_ty();
- fn_ty(); // expected-error {{function types cannot be value-initialized}}
+ fn_ty(); // expected-error {{cannot create object of function type 'fn_ty'}}
+ fn_ty(0); // expected-error {{functional-style cast from 'int' to 'fn_ty'}}
+ fn_ty(0, 0); // expected-error {{cannot create object of function type 'fn_ty'}}
+#if __cplusplus >= 201103L
+ fn_ty{}; // expected-error {{cannot create object of function type 'fn_ty'}}
+ fn_ty{0}; // expected-error {{cannot create object of function type 'fn_ty'}}
+ fn_ty{0, 0}; // expected-error {{cannot create object of function type 'fn_ty'}}
+ fn_ty({}); // expected-error {{cannot create object of function type 'fn_ty'}}
+#endif
int v4 = int();
int v5 = int; // expected-error {{expected '(' for function-style cast or type construction}}
typedef int T;
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index c53b02774aca..9da59b93c503 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -1,20 +1,28 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -fms-extensions -Wno-microsoft %s
+
#define T(b) (b) ? 1 : -1
#define F(b) (b) ? -1 : 1
struct NonPOD { NonPOD(int); };
+typedef NonPOD NonPODAr[10];
+typedef NonPOD NonPODArNB[];
+typedef NonPOD NonPODArMB[10][2];
// PODs
enum Enum { EV };
struct POD { Enum e; int i; float f; NonPOD* p; };
struct Empty {};
typedef Empty EmptyAr[10];
+typedef Empty EmptyArNB[];
+typedef Empty EmptyArMB[1][2];
typedef int Int;
typedef Int IntAr[10];
typedef Int IntArNB[];
class Statics { static int priv; static NonPOD np; };
union EmptyUnion {};
-union IncompleteUnion;
+union IncompleteUnion; // expected-note {{forward declaration of 'IncompleteUnion'}}
union Union { int i; float f; };
struct HasFunc { void f (); };
struct HasOp { void operator *(); };
@@ -31,6 +39,9 @@ struct HasAnonymousUnion {
typedef int Vector __attribute__((vector_size(16)));
typedef int VectorExt __attribute__((ext_vector_type(4)));
+using ComplexFloat = _Complex float;
+using ComplexInt = _Complex int;
+
// Not PODs
typedef const void cvoid;
struct Derives : POD {};
@@ -38,6 +49,10 @@ typedef Derives DerivesAr[10];
typedef Derives DerivesArNB[];
struct DerivesEmpty : Empty {};
struct HasCons { HasCons(int); };
+struct HasDefaultCons { HasDefaultCons() = default; };
+struct HasExplicitDefaultCons { explicit HasExplicitDefaultCons() = default; };
+struct HasInheritedCons : HasDefaultCons { using HasDefaultCons::HasDefaultCons; };
+struct HasNoInheritedCons : HasCons {};
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
struct HasNoThrowMoveAssign {
@@ -48,8 +63,15 @@ struct HasNoExceptNoThrowMoveAssign {
const HasNoExceptNoThrowMoveAssign&&) noexcept;
};
struct HasThrowMoveAssign {
- HasThrowMoveAssign& operator=(
- const HasThrowMoveAssign&&) throw(POD); };
+ HasThrowMoveAssign& operator=(const HasThrowMoveAssign&&)
+#if __cplusplus <= 201402L
+ throw(POD);
+#else
+ noexcept(false);
+#endif
+};
+
+
struct HasNoExceptFalseMoveAssign {
HasNoExceptFalseMoveAssign& operator=(
const HasNoExceptFalseMoveAssign&&) noexcept(false); };
@@ -81,6 +103,7 @@ struct HasDest { ~HasDest(); };
class HasPriv { int priv; };
class HasProt { protected: int prot; };
struct HasRef { int i; int& ref; HasRef() : i(0), ref(i) {} };
+struct HasRefAggregate { int i; int& ref; };
struct HasNonPOD { NonPOD np; };
struct HasVirt { virtual void Virt() {}; };
typedef NonPOD NonPODAr[10];
@@ -152,7 +175,12 @@ struct VariadicCtor {
};
struct ThrowingDtor {
- ~ThrowingDtor() throw(int);
+ ~ThrowingDtor()
+#if __cplusplus <= 201402L
+ throw(int);
+#else
+ noexcept(false);
+#endif
};
struct NoExceptDtor {
@@ -163,6 +191,20 @@ struct NoThrowDtor {
~NoThrowDtor() throw();
};
+struct ACompleteType {};
+struct AnIncompleteType; // expected-note 1+ {{forward declaration of 'AnIncompleteType'}}
+typedef AnIncompleteType AnIncompleteTypeAr[42];
+typedef AnIncompleteType AnIncompleteTypeArNB[];
+typedef AnIncompleteType AnIncompleteTypeArMB[1][10];
+
+struct HasInClassInit {
+ int x = 42;
+};
+
+struct HasPrivateBase : private ACompleteType {};
+struct HasProtectedBase : protected ACompleteType {};
+struct HasVirtBase : virtual ACompleteType {};
+
void is_pod()
{
{ int arr[T(__is_pod(int))]; }
@@ -452,6 +494,83 @@ void is_floating_point()
int t31[F(__is_floating_point(IntArNB))];
}
+template <class T>
+struct AggregateTemplate {
+ T value;
+};
+
+template <class T>
+struct NonAggregateTemplate {
+ T value;
+ NonAggregateTemplate();
+};
+
+void is_aggregate()
+{
+ constexpr bool TrueAfterCpp11 = __cplusplus > 201103L;
+ constexpr bool TrueAfterCpp14 = __cplusplus > 201402L;
+
+ __is_aggregate(AnIncompleteType); // expected-error {{incomplete type}}
+ __is_aggregate(AnIncompleteTypeAr); // expected-error {{incomplete type}}
+ __is_aggregate(AnIncompleteTypeArNB); // expected-error {{incomplete type}}
+ __is_aggregate(AnIncompleteTypeArMB); // expected-error {{incomplete type}}
+ __is_aggregate(IncompleteUnion); // expected-error {{incomplete type}}
+
+ static_assert(!__is_aggregate(NonPOD), "");
+ static_assert(__is_aggregate(NonPODAr), "");
+ static_assert(__is_aggregate(NonPODArNB), "");
+ static_assert(__is_aggregate(NonPODArMB), "");
+
+ static_assert(!__is_aggregate(Enum), "");
+ static_assert(__is_aggregate(POD), "");
+ static_assert(__is_aggregate(Empty), "");
+ static_assert(__is_aggregate(EmptyAr), "");
+ static_assert(__is_aggregate(EmptyArNB), "");
+ static_assert(__is_aggregate(EmptyArMB), "");
+ static_assert(!__is_aggregate(void), "");
+ static_assert(!__is_aggregate(const volatile void), "");
+ static_assert(!__is_aggregate(int), "");
+ static_assert(__is_aggregate(IntAr), "");
+ static_assert(__is_aggregate(IntArNB), "");
+ static_assert(__is_aggregate(EmptyUnion), "");
+ static_assert(__is_aggregate(Union), "");
+ static_assert(__is_aggregate(Statics), "");
+ static_assert(__is_aggregate(HasFunc), "");
+ static_assert(__is_aggregate(HasOp), "");
+ static_assert(__is_aggregate(HasAssign), "");
+ static_assert(__is_aggregate(HasAnonymousUnion), "");
+
+ static_assert(__is_aggregate(Derives) == TrueAfterCpp14, "");
+ static_assert(__is_aggregate(DerivesAr), "");
+ static_assert(__is_aggregate(DerivesArNB), "");
+ static_assert(!__is_aggregate(HasCons), "");
+ static_assert(__is_aggregate(HasDefaultCons), "");
+ static_assert(!__is_aggregate(HasExplicitDefaultCons), "");
+ static_assert(!__is_aggregate(HasInheritedCons), "");
+ static_assert(__is_aggregate(HasNoInheritedCons) == TrueAfterCpp14, "");
+ static_assert(__is_aggregate(HasCopyAssign), "");
+ static_assert(!__is_aggregate(NonTrivialDefault), "");
+ static_assert(__is_aggregate(HasDest), "");
+ static_assert(!__is_aggregate(HasPriv), "");
+ static_assert(!__is_aggregate(HasProt), "");
+ static_assert(__is_aggregate(HasRefAggregate), "");
+ static_assert(__is_aggregate(HasNonPOD), "");
+ static_assert(!__is_aggregate(HasVirt), "");
+ static_assert(__is_aggregate(VirtAr), "");
+ static_assert(__is_aggregate(HasInClassInit) == TrueAfterCpp11, "");
+ static_assert(!__is_aggregate(HasPrivateBase), "");
+ static_assert(!__is_aggregate(HasProtectedBase), "");
+ static_assert(!__is_aggregate(HasVirtBase), "");
+
+ static_assert(__is_aggregate(AggregateTemplate<int>), "");
+ static_assert(!__is_aggregate(NonAggregateTemplate<int>), "");
+
+ static_assert(__is_aggregate(Vector), ""); // Extension supported by GCC and Clang
+ static_assert(__is_aggregate(VectorExt), "");
+ static_assert(__is_aggregate(ComplexInt), "");
+ static_assert(__is_aggregate(ComplexFloat), "");
+}
+
void is_arithmetic()
{
int t01[T(__is_arithmetic(float))];
@@ -481,9 +600,6 @@ void is_arithmetic()
int t31[F(__is_arithmetic(IntArNB))];
}
-struct ACompleteType {};
-struct AnIncompleteType;
-
void is_complete_type()
{
int t01[T(__is_complete_type(float))];
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index 7a23f3cef2c4..e4928b8566c6 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -std=c++1z -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -Wno-unused-lambda-capture -std=c++1z -verify %s
// definitions for std::move
namespace std {
diff --git a/test/SemaCXX/virtual-base-used.cpp b/test/SemaCXX/virtual-base-used.cpp
index c46cf5a8c9ef..f0dcc969e8da 100644
--- a/test/SemaCXX/virtual-base-used.cpp
+++ b/test/SemaCXX/virtual-base-used.cpp
@@ -1,89 +1,216 @@
// RUN: %clang_cc1 -fsyntax-only -triple %itanium_abi_triple -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple %itanium_abi_triple -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -triple %itanium_abi_triple -verify -std=c++11 %s
// RUN: %clang_cc1 -fsyntax-only -triple %ms_abi_triple -DMSABI -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple %ms_abi_triple -DMSABI -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -triple %ms_abi_triple -DMSABI -verify -std=c++11 %s
// PR7800
// The Microsoft ABI doesn't have the concept of key functions, so we have different
// expectations about when functions are first required for that case.
+class NoDestroy { ~NoDestroy(); };
+#if __cplusplus <= 199711L
+// expected-note@-2 3 {{declared private here}}
#ifdef MSABI
-// expected-note@+2 3 {{declared private here}}
+// expected-note@-4 3 {{declared private here}}
#endif
-class NoDestroy { ~NoDestroy(); }; // expected-note 3 {{declared private here}}
+#endif
+
struct A {
virtual ~A();
+#if __cplusplus >= 201103L
+ // expected-note@-2 3 {{overridden virtual function is here}}
+#endif
};
+struct B : public virtual A {
+#if __cplusplus >= 201103L
+// expected-error@-2 {{deleted function '~B' cannot override a non-deleted function}}
+// expected-note@-3 {{overridden virtual function is here}}
+#endif
+
+ NoDestroy x;
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{field of type 'NoDestroy' has private destructor}}
#ifdef MSABI
-// expected-error@+3 {{field of type 'NoDestroy' has private destructor}}
+ // expected-error@-4 {{field of type 'NoDestroy' has private destructor}}
#endif
-struct B : public virtual A {
- NoDestroy x; // expected-error {{field of type 'NoDestroy' has private destructor}}
-};
+#else
+ // expected-note@-7 {{destructor of 'B' is implicitly deleted because field 'x' has an inaccessible destructor}}
#ifdef MSABI
-// expected-note@+3 {{implicit default constructor for 'B' first required here}}
-// expected-note@+2 {{implicit destructor for 'B' first required here}}
+ // expected-note@-9 {{default constructor of 'B' is implicitly deleted because field 'x' has an inaccessible destructor}}
+#endif
#endif
+};
+
struct D : public virtual B {
+#if __cplusplus <= 199711L
+#ifdef MSABI
+// expected-note@-3 {{implicit default constructor for 'B' first required here}}
+// expected-note@-4 {{implicit destructor for 'B' first required here}}
+#endif
+#else
+#ifdef MSABI
+// expected-note@-8 {{default constructor of 'D' is implicitly deleted because base class 'B' has a deleted default constructor}}
+#endif
+#endif
virtual void foo();
~D();
+#if __cplusplus >= 201103L
+ //expected-error@-2 {{non-deleted function '~D' cannot override a deleted function}}
+#endif
};
+
#ifdef MSABI
-D d; // expected-note {{implicit default constructor for 'D' first required here}}
+D d;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit default constructor for 'D' first required here}}
#else
-void D::foo() { // expected-note {{implicit destructor for 'B' first required here}}
+// expected-error@-4 {{call to implicitly-deleted default constructor of 'D'}}
+#endif
+#else
+void D::foo() {
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'B' first required here}}
+#endif
}
#endif
+struct E : public virtual A {
+#if __cplusplus >= 201103L
+// expected-error@-2 {{deleted function '~E' cannot override a non-deleted function}}
+// expected-note@-3 {{overridden virtual function is here}}
+#endif
+
+ NoDestroy x;
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{field of type 'NoDestroy' has private destructor}}
#ifdef MSABI
-// expected-error@+3 {{field of type 'NoDestroy' has private destructor}}
+ // expected-error@-4 {{field of type 'NoDestroy' has private destructor}}
#endif
-struct E : public virtual A {
- NoDestroy x; // expected-error {{field of type 'NoDestroy' has private destructor}}
-};
+#else
+ // expected-note@-7 {{destructor of 'E' is implicitly deleted because field 'x' has an inaccessible destructor}}
#ifdef MSABI
-// expected-note@+2 {{implicit default constructor for 'E' first required here}}
+ // expected-note@-9 {{default constructor of 'E' is implicitly deleted because field 'x' has an inaccessible destructor}}
+#endif
#endif
-struct F : public E { // expected-note {{implicit destructor for 'E' first required here}}
};
+
+struct F : public E {
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'E' first required here}}
#ifdef MSABI
-// expected-note@+2 {{implicit default constructor for 'F' first required here}}
+// expected-note@-4 {{implicit default constructor for 'E' first required here}}
+#endif
+#else
+// expected-error@-7 {{non-deleted function '~F' cannot override a deleted function}}
+// expected-note@-8 {{while declaring the implicit destructor for 'F'}}
+// expected-note@-9 {{overridden virtual function is here}}
+#ifdef MSABI
+// expected-note@-11 {{default constructor of 'F' is implicitly deleted because base class 'E' has a deleted default constructor}}
+#endif
#endif
+};
+
+
struct G : public virtual F {
+#ifdef MSABI
+#if __cplusplus <= 199711L
+// expected-note@-3 {{implicit default constructor for 'F' first required here}}
+#else
+// expected-note@-5 {{default constructor of 'G' is implicitly deleted because base class 'F' has a deleted default constructor}}
+#endif
+#endif
+
virtual void foo();
~G();
+#if __cplusplus >= 201103L
+ //expected-error@-2 {{non-deleted function '~G' cannot override a deleted function}}
+#endif
};
+
#ifdef MSABI
-G g; // expected-note {{implicit default constructor for 'G' first required here}}
+G g;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit default constructor for 'G' first required here}}
+#else
+// expected-error@-4 {{call to implicitly-deleted default constructor of 'G'}}
+#endif
#else
-void G::foo() { // expected-note {{implicit destructor for 'F' first required here}}
+void G::foo() {
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'F' first required here}}
+#endif
}
#endif
+struct H : public virtual A {
+#if __cplusplus >= 201103L
+// expected-error@-2 {{deleted function '~H' cannot override a non-deleted function}}
+// expected-note@-3 {{overridden virtual function is here}}
+#else
#ifdef MSABI
-// expected-note@+3 {{'H' declared here}}
-// expected-error@+3 {{field of type 'NoDestroy' has private destructor}}
+// expected-note@-6 {{'H' declared here}}
#endif
-struct H : public virtual A {
- NoDestroy x; // expected-error {{field of type 'NoDestroy' has private destructor}}
-};
+#endif
+
+ NoDestroy x;
+#if __cplusplus <= 199711L
+ // expected-error@-2 {{field of type 'NoDestroy' has private destructor}}
#ifdef MSABI
-// expected-error@+3 {{implicit default constructor for 'I' must explicitly initialize the base class 'H' which does not have a default constructor}}
-// expected-note@+2 {{implicit destructor for 'H' first required here}}
+ // expected-error@-4 {{field of type 'NoDestroy' has private destructor}}
+#endif
+#else
+ // expected-note@-7 {{destructor of 'H' is implicitly deleted because field 'x' has an inaccessible destructor}}
+#ifdef MSABI
+ // expected-note@-9 {{default constructor of 'H' is implicitly deleted because field 'x' has an inaccessible destructor}}
+#endif
#endif
+};
+
struct I : public virtual H {
+#ifdef MSABI
+#if __cplusplus <= 199711L
+// expected-error@-3 {{implicit default constructor for 'I' must explicitly initialize the base class 'H' which does not have a default constructor}}
+// expected-note@-4 {{implicit destructor for 'H' first required here}}
+#else
+// expected-note@-6 {{default constructor of 'I' is implicitly deleted because base class 'H' has a deleted default constructor}}
+#endif
+#endif
+
~I();
+#if __cplusplus >= 201103L
+// expected-error@-2 {{non-deleted function '~I' cannot override a deleted function}}
+#endif
};
+
+struct J : public I {
#ifdef MSABI
-// expected-note@+3 {{implicit default constructor for 'H' first required here}}
-// expected-note@+2 {{implicit default constructor for 'I' first required here}}
+#if __cplusplus <= 199711L
+// expected-note@-3 {{implicit default constructor for 'H' first required here}}
+// expected-note@-4 {{implicit default constructor for 'I' first required here}}
+#else
+// expected-note@-6 {{default constructor of 'J' is implicitly deleted because base class 'I' has a deleted default constructor}}
#endif
-struct J : public I {
+#endif
+
virtual void foo();
~J();
};
+
#ifdef MSABI
-J j; // expected-note {{implicit default constructor for 'J' first required here}}
+J j;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit default constructor for 'J' first required here}}
#else
-void J::foo() { // expected-note {{implicit destructor for 'H' first required here}}
+// expected-error@-4 {{call to implicitly-deleted default constructor of 'J'}}
+#endif
+
+#else
+void J::foo() {
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'H' first required here}}
+#endif
}
#endif
diff --git a/test/SemaCXX/virtual-member-functions-key-function.cpp b/test/SemaCXX/virtual-member-functions-key-function.cpp
index 80ce0298ba98..d5bd10c81f03 100644
--- a/test/SemaCXX/virtual-member-functions-key-function.cpp
+++ b/test/SemaCXX/virtual-member-functions-key-function.cpp
@@ -1,20 +1,51 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
struct A {
virtual ~A();
+#if __cplusplus >= 201103L
+// expected-note@-2 2 {{overridden virtual function is here}}
+#endif
};
-struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}}
- B() { } // expected-note {{implicit destructor for 'B' first required here}}
- void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
+struct B : A {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{no suitable member 'operator delete' in 'B'}}
+#else
+// expected-error@-4 {{deleted function '~B' cannot override a non-deleted function}}
+// expected-note@-5 {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+#endif
+ B() { }
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'B' first required here}}
+#endif
+
+ void operator delete(void *, int);
+#if __cplusplus <= 199711L
+// expected-note@-2 {{'operator delete' declared here}}
+#endif
};
-struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
- void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
+struct C : A {
+#if __cplusplus <= 199711L
+// expected-error@-2 {{no suitable member 'operator delete' in 'C'}}
+#else
+// expected-error@-4 {{deleted function '~C' cannot override a non-deleted function}}
+// expected-note@-5 {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+#endif
+ void operator delete(void *, int);
+#if __cplusplus <= 199711L
+// expected-note@-2 {{'operator delete' declared here}}
+#endif
};
void f() {
(void)new B;
- (void)new C; // expected-note {{implicit destructor for 'C' first required here}}
+ (void)new C;
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor for 'C' first required here}}
+#endif
}
// Make sure that the key-function computation is consistent when the
diff --git a/test/SemaCXX/warn-bitfield-enum-conversion.cpp b/test/SemaCXX/warn-bitfield-enum-conversion.cpp
new file mode 100644
index 000000000000..7e7a202f8d2b
--- /dev/null
+++ b/test/SemaCXX/warn-bitfield-enum-conversion.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -verify %s -Wbitfield-enum-conversion
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux -verify %s -Wbitfield-enum-conversion
+
+enum TwoBits { Hi1 = 3 } two_bits;
+enum TwoBitsSigned { Lo2 = -2, Hi2 = 1 } two_bits_signed;
+enum ThreeBits { Hi3 = 7 } three_bits;
+enum ThreeBitsSigned { Lo4 = -4, Hi4 = 3 } three_bits_signed;
+enum TwoBitsFixed : unsigned { Hi5 = 3 } two_bits_fixed;
+
+struct Foo {
+ unsigned two_bits : 2; // expected-note 2 {{widen this field to 3 bits}} expected-note 2 {{type signed}}
+ int two_bits_signed : 2; // expected-note 2 {{widen this field to 3 bits}} expected-note 1 {{type unsigned}}
+ unsigned three_bits : 3; // expected-note 2 {{type signed}}
+ int three_bits_signed : 3; // expected-note 1 {{type unsigned}}
+
+#ifdef _WIN32
+ // expected-note@+2 {{type unsigned}}
+#endif
+ ThreeBits three_bits_enum : 3;
+ ThreeBits four_bits_enum : 4;
+};
+
+void f() {
+ Foo f;
+
+ f.two_bits = two_bits;
+ f.two_bits = two_bits_signed; // expected-warning {{negative enumerators}}
+ f.two_bits = three_bits; // expected-warning {{not wide enough}}
+ f.two_bits = three_bits_signed; // expected-warning {{negative enumerators}} expected-warning {{not wide enough}}
+ f.two_bits = two_bits_fixed;
+
+ f.two_bits_signed = two_bits; // expected-warning {{needs an extra bit}}
+ f.two_bits_signed = two_bits_signed;
+ f.two_bits_signed = three_bits; // expected-warning {{not wide enough}}
+ f.two_bits_signed = three_bits_signed; // expected-warning {{not wide enough}}
+
+ f.three_bits = two_bits;
+ f.three_bits = two_bits_signed; // expected-warning {{negative enumerators}}
+ f.three_bits = three_bits;
+ f.three_bits = three_bits_signed; // expected-warning {{negative enumerators}}
+
+ f.three_bits_signed = two_bits;
+ f.three_bits_signed = two_bits_signed;
+ f.three_bits_signed = three_bits; // expected-warning {{needs an extra bit}}
+ f.three_bits_signed = three_bits_signed;
+
+#ifdef _WIN32
+ // Enums on Windows are always implicitly 'int', which is signed, so you need
+ // an extra bit to store values that set the MSB. This is not true on SysV
+ // platforms like Linux.
+ // expected-warning@+2 {{needs an extra bit}}
+#endif
+ f.three_bits_enum = three_bits;
+ f.four_bits_enum = three_bits;
+
+ // Explicit casts suppress the warning.
+ f.two_bits = (unsigned)three_bits_signed;
+ f.two_bits = static_cast<unsigned>(three_bits_signed);
+}
diff --git a/test/SemaCXX/warn-bool-conversion.cpp b/test/SemaCXX/warn-bool-conversion.cpp
index b0c8d0d19d14..ab563aa68988 100644
--- a/test/SemaCXX/warn-bool-conversion.cpp
+++ b/test/SemaCXX/warn-bool-conversion.cpp
@@ -1,19 +1,66 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
namespace BooleanFalse {
-int* j = false; // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
-
-void foo(int* i, int *j=(false)) // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+int* j = false;
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+#else
+// expected-error@-4 {{cannot initialize a variable of type 'int *' with an rvalue of type 'bool'}}
+#endif
+
+#if __cplusplus <= 199711L
+// expected-warning@+6 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+#else
+// expected-error@+4 {{cannot initialize a parameter of type 'int *' with an rvalue of type 'bool'}}
+// expected-note@+3 {{passing argument to parameter 'j' here}}
+// expected-note@+2 6 {{candidate function not viable: requires 2 arguments, but 1 was provided}}
+#endif
+void foo(int* i, int *j=(false))
{
- foo(false); // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
- foo((int*)false); // no-warning: explicit cast
- foo(0); // no-warning: not a bool, even though its convertible to bool
-
- foo(false == true); // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
- foo((42 + 24) < 32); // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+ foo(false);
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+#else
+// expected-error@-4 {{no matching function for call to 'foo'}}
+#endif
+
+ foo((int*)false);
+#if __cplusplus <= 199711L
+// no-warning: explicit cast
+#else
+// expected-error@-4 {{no matching function for call to 'foo'}}
+#endif
+
+ foo(0);
+#if __cplusplus <= 199711L
+// no-warning: not a bool, even though its convertible to bool
+#else
+// expected-error@-4 {{no matching function for call to 'foo'}}
+#endif
+
+ foo(false == true);
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+#else
+// expected-error@-4 {{no matching function for call to 'foo'}}
+#endif
+
+ foo((42 + 24) < 32);
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+#else
+// expected-error@-4 {{no matching function for call to 'foo'}}
+#endif
const bool kFlag = false;
- foo(kFlag); // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+ foo(kFlag);
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+#else
+// expected-error@-4 {{no matching function for call to 'foo'}}
+#endif
}
char f(struct Undefined*);
diff --git a/test/SemaCXX/warn-inconsistent-missing-destructor-override b/test/SemaCXX/warn-inconsistent-missing-destructor-override
new file mode 100644
index 000000000000..75e9ba8d141d
--- /dev/null
+++ b/test/SemaCXX/warn-inconsistent-missing-destructor-override
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify -Winconsistent-missing-destructor-override
+
+class A {
+ public:
+ ~A() {}
+ void virtual run() {}
+};
+
+class B : public A {
+ public:
+ void run() override {}
+ ~B() {}
+};
+
+class C {
+ public:
+ virtual void run() {}
+ virtual ~C() {} // expected-note 2{{overridden virtual function is here}}
+};
+
+class D : public C {
+ public:
+ void run() override {}
+ ~D() {}
+ // expected-warning@-1 {{'~D' overrides a destructor but is not marked 'override'}}
+};
+
+class E : public C {
+ public:
+ void run() override {}
+ virtual ~E() {}
+ // expected-warning@-1 {{'~E' overrides a destructor but is not marked 'override'}}
+};
diff --git a/test/SemaCXX/warn-shadow.cpp b/test/SemaCXX/warn-shadow.cpp
index 1316b6dd8871..0b84ef50caa1 100644
--- a/test/SemaCXX/warn-shadow.cpp
+++ b/test/SemaCXX/warn-shadow.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -Wshadow-all %s
+// RUN: %clang_cc1 -verify -fsyntax-only -std=c++11 -Wshadow-all %s
namespace {
int i; // expected-note {{previous declaration is here}}
@@ -7,14 +7,21 @@ namespace {
namespace one {
namespace two {
int j; // expected-note {{previous declaration is here}}
+ typedef int jj; // expected-note 2 {{previous declaration is here}}
+ using jjj=int; // expected-note 2 {{previous declaration is here}}
}
}
namespace xx {
int m;
+ typedef int mm;
+ using mmm=int;
+
}
namespace yy {
int m;
+ typedef char mm;
+ using mmm=char;
}
using namespace one::two;
@@ -25,14 +32,19 @@ void foo() {
int i; // expected-warning {{declaration shadows a variable in namespace '(anonymous)'}}
int j; // expected-warning {{declaration shadows a variable in namespace 'one::two'}}
int m;
+ int mm;
+ int mmm;
}
class A {
- static int data; // expected-note {{previous declaration}}
- // expected-note@+1 {{previous declaration}}
+ static int data; // expected-note 1 {{previous declaration}}
+ // expected-note@+1 1 {{previous declaration}}
int field;
int f1, f2, f3, f4; // expected-note 8 {{previous declaration is here}}
+ typedef int a1; // expected-note 2 {{previous declaration}}
+ using a2=int; // expected-note 2 {{previous declaration}}
+
// The initialization is safe, but the modifications are not.
A(int f1, int f2, int f3, int f4) // expected-note-re 4 {{variable 'f{{[0-4]}}' is declared here}}
: f1(f1) {
@@ -50,9 +62,41 @@ class A {
void test() {
char *field; // expected-warning {{declaration shadows a field of 'A'}}
char *data; // expected-warning {{declaration shadows a static data member of 'A'}}
+ char *a1; // no warning
+ char *a2; // no warning
+ char *jj; // no warning
+ char *jjj; // no warning
+ }
+
+ void test2() {
+ typedef char field; // no warning
+ typedef char data; // no warning
+ typedef char a1; // expected-warning {{declaration shadows a typedef in 'A'}}
+ typedef char a2; // expected-warning {{declaration shadows a type alias in 'A'}}
+ typedef char jj; // expected-warning {{declaration shadows a typedef in namespace 'one::two'}}
+ typedef char jjj; // expected-warning {{declaration shadows a type alias in namespace 'one::two'}}
+ }
+
+ void test3() {
+ using field=char; // no warning
+ using data=char; // no warning
+ using a1=char; // expected-warning {{declaration shadows a typedef in 'A'}}
+ using a2=char; // expected-warning {{declaration shadows a type alias in 'A'}}
+ using jj=char; // expected-warning {{declaration shadows a typedef in namespace 'one::two'}}
+ using jjj=char; // expected-warning {{declaration shadows a type alias in namespace 'one::two'}}
}
};
+struct path {
+ using value_type = char;
+ typedef char value_type2;
+ struct iterator {
+ using value_type = path; // no warning
+ typedef path value_type2; // no warning
+ };
+};
+
+
// TODO: this should warn, <rdar://problem/5018057>
class B : A {
int data;
@@ -63,6 +107,8 @@ class B : A {
namespace rdar8900456 {
struct Foo {
static void Baz();
+ static void Baz1();
+ static void Baz2();
private:
int Bar;
};
@@ -70,6 +116,14 @@ private:
void Foo::Baz() {
double Bar = 12; // Don't warn.
}
+
+void Foo::Baz1() {
+ typedef int Bar; // Don't warn.
+}
+
+void Foo::Baz2() {
+ using Bar=int; // Don't warn.
+}
}
// http://llvm.org/PR9160
@@ -87,7 +141,9 @@ struct S {
};
}
-extern int bob; // expected-note {{previous declaration is here}}
+extern int bob; // expected-note 1 {{previous declaration is here}}
+typedef int bob1; // expected-note 2 {{previous declaration is here}}
+using bob2=int; // expected-note 2 {{previous declaration is here}}
// rdar://8883302
void rdar8883302() {
@@ -96,6 +152,20 @@ void rdar8883302() {
void test8() {
int bob; // expected-warning {{declaration shadows a variable in the global namespace}}
+ int bob1; //no warning
+ int bob2; // no warning
+}
+
+void test9() {
+ typedef int bob; // no warning
+ typedef int bob1; // expected-warning {{declaration shadows a typedef in the global namespace}}
+ typedef int bob2; // expected-warning {{declaration shadows a type alias in the global namespace}}
+}
+
+void test10() {
+ using bob=int; // no warning
+ using bob1=int; // expected-warning {{declaration shadows a typedef in the global namespace}}
+ using bob2=int; // expected-warning {{declaration shadows a type alias in the global namespace}}
}
namespace rdar29067894 {
@@ -104,6 +174,35 @@ void avoidWarningWhenRedefining(int b) { // expected-note {{previous definition
int a = 0; // expected-note {{previous definition is here}}
int a = 1; // expected-error {{redefinition of 'a'}}
int b = 2; // expected-error {{redefinition of 'b'}}
+
+ using c=char; // expected-note {{previous definition is here}}
+ using c=int; // expected-error {{type alias redefinition with different types ('int' vs 'char')}}
+
+ typedef char d; // expected-note {{previous definition is here}}
+ typedef int d; // expected-error {{typedef redefinition with different types ('int' vs 'char')}}
+
+ using e=char; // expected-note {{previous definition is here}}
+ typedef int e; // expected-error {{type alias redefinition with different types ('int' vs 'char')}}
+
+ int f; // expected-note {{previous definition is here}}
+ using f=int; // expected-error {{redefinition of 'f'}}
+
+ using g=int; // expected-note {{previous definition is here}}
+ int g; // expected-error {{redefinition of 'g'}}
+
+ typedef int h; // expected-note {{previous definition is here}}
+ int h; // expected-error {{redefinition of 'h'}}
+
+ int k; // expected-note {{previous definition is here}}
+ typedef int k; // expected-error {{redefinition of 'k'}}
+
+ using l=char; // no warning or error.
+ using l=char; // no warning or error.
+ typedef char l; // no warning or error.
+
+ typedef char n; // no warning or error.
+ typedef char n; // no warning or error.
+ using n=char; // no warning or error.
}
}
diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp
index 6f9e7de4176d..b43e24a897bf 100644
--- a/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 %s
#define LOCKABLE __attribute__ ((lockable))
#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
@@ -1266,8 +1268,11 @@ public:
void foo3(FooLate *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu) { }
void foo4(FooLate *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu);
- static void foo5() EXCLUSIVE_LOCKS_REQUIRED(mu); // \
- // expected-error {{invalid use of member 'mu' in static member function}}
+ static void foo5() EXCLUSIVE_LOCKS_REQUIRED(mu);
+//FIXME: Bug 32066 - Error should be emitted irrespective of C++ dialect
+#if __cplusplus <= 199711L
+ // expected-error@-3 {{invalid use of member 'mu' in static member function}}
+#endif
template <class T>
void foo6() EXCLUSIVE_LOCKS_REQUIRED(T::statmu) { }
@@ -1461,15 +1466,24 @@ class Foo {
mutable Mutex mu;
int a GUARDED_BY(mu);
- static int si GUARDED_BY(mu); // \
- // expected-error {{invalid use of non-static data member 'mu'}}
+ static int si GUARDED_BY(mu);
+//FIXME: Bug 32066 - Error should be emitted irrespective of C++ dialect
+#if __cplusplus <= 199711L
+ // expected-error@-3 {{invalid use of non-static data member 'mu'}}
+#endif
- static void foo() EXCLUSIVE_LOCKS_REQUIRED(mu); // \
- // expected-error {{invalid use of member 'mu' in static member function}}
+ static void foo() EXCLUSIVE_LOCKS_REQUIRED(mu);
+//FIXME: Bug 32066 - Error should be emitted irrespective of C++ dialect
+#if __cplusplus <= 199711L
+ // expected-error@-3 {{invalid use of member 'mu' in static member function}}
+#endif
friend FooStream& operator<<(FooStream& s, const Foo& f)
- EXCLUSIVE_LOCKS_REQUIRED(mu); // \
- // expected-error {{invalid use of non-static data member 'mu'}}
+ EXCLUSIVE_LOCKS_REQUIRED(mu);
+//FIXME: Bug 32066 - Error should be emitted irrespective of C++ dialect
+#if __cplusplus <= 199711L
+ // expected-error@-3 {{invalid use of non-static data member 'mu'}}
+#endif
};
diff --git a/test/SemaCXX/warn-unused-lambda-capture.cpp b/test/SemaCXX/warn-unused-lambda-capture.cpp
new file mode 100644
index 000000000000..48f8bfea7e9a
--- /dev/null
+++ b/test/SemaCXX/warn-unused-lambda-capture.cpp
@@ -0,0 +1,188 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++1z %s
+
+class NonTrivialConstructor {
+public:
+ NonTrivialConstructor() {}
+};
+
+class NonTrivialCopyConstructor {
+public:
+ NonTrivialCopyConstructor() = default;
+ NonTrivialCopyConstructor(const NonTrivialCopyConstructor &) {}
+};
+
+class NonTrivialDestructor {
+public:
+ ~NonTrivialDestructor() {}
+};
+
+class Trivial {
+public:
+ Trivial() = default;
+ Trivial(int a) {}
+};
+
+int side_effect() {
+ return 42;
+}
+
+void test() {
+ int i = 0;
+ const int k = 0;
+
+ auto captures_nothing = [] {};
+
+ auto captures_nothing_by_value = [=] {};
+ auto captures_nothing_by_reference = [&] {};
+
+ auto implicit_by_value = [=]() mutable { i++; };
+ auto implicit_by_reference = [&] { i++; };
+
+ auto explicit_by_value_used = [i] { return i + 1; };
+ auto explicit_by_value_used_void = [i] { (void)i; };
+ auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
+ auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
+ auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
+ auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
+
+ auto explicit_by_reference_used = [&i] { i++; };
+ auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}
+
+ auto explicit_initialized_reference_used = [&j = i] { return j + 1; };
+ auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}}
+
+ auto explicit_initialized_value_used = [j = 1] { return j + 1; };
+ auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}}
+ auto explicit_initialized_value_non_trivial_constructor = [j = NonTrivialConstructor()]{};
+ auto explicit_initialized_value_non_trivial_destructor = [j = NonTrivialDestructor()]{};
+ auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}
+ auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
+ auto explicit_initialized_value_with_side_effect = [j = side_effect()]{};
+
+ auto nested = [&i] {
+ auto explicit_by_value_used = [i] { return i + 1; };
+ auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
+ };
+
+ Trivial trivial;
+ auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}}
+
+ NonTrivialConstructor cons;
+ auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}}
+
+ NonTrivialCopyConstructor copy_cons;
+ auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {};
+
+ NonTrivialDestructor dest;
+ auto explicit_by_value_non_trivial_destructor = [dest] {};
+
+ volatile int v;
+ auto explicit_by_value_volatile = [v] {};
+}
+
+class TrivialThis : Trivial {
+ void test() {
+ auto explicit_this_used = [this] { return i; };
+ auto explicit_this_used_void = [this] { (void)this; };
+ auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}
+ auto explicit_star_this_used = [*this] { return i; };
+ auto explicit_star_this_used_void = [*this] { (void)this; };
+ auto explicit_star_this_unused = [*this] {}; // expected-warning{{lambda capture 'this' is not used}}
+ }
+ int i;
+};
+
+class NonTrivialConstructorThis : NonTrivialConstructor {
+ void test() {
+ auto explicit_this_used = [this] { return i; };
+ auto explicit_this_used_void = [this] { (void)this; };
+ auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}
+ auto explicit_star_this_used = [*this] { return i; };
+ auto explicit_star_this_used_void = [*this] { (void)this; };
+ auto explicit_star_this_unused = [*this] {}; // expected-warning{{lambda capture 'this' is not used}}
+ }
+ int i;
+};
+
+class NonTrivialCopyConstructorThis : NonTrivialCopyConstructor {
+ void test() {
+ auto explicit_this_used = [this] { return i; };
+ auto explicit_this_used_void = [this] { (void)this; };
+ auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}
+ auto explicit_star_this_used = [*this] { return i; };
+ auto explicit_star_this_used_void = [*this] { (void)this; };
+ auto explicit_star_this_unused = [*this] {};
+ }
+ int i;
+};
+
+class NonTrivialDestructorThis : NonTrivialDestructor {
+ void test() {
+ auto explicit_this_used = [this] { return i; };
+ auto explicit_this_used_void = [this] { (void)this; };
+ auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}
+ auto explicit_star_this_used = [*this] { return i; };
+ auto explicit_star_this_used_void = [*this] { (void)this; };
+ auto explicit_star_this_unused = [*this] {};
+ }
+ int i;
+};
+
+template <typename T>
+void test_templated() {
+ int i = 0;
+ const int k = 0;
+
+ auto captures_nothing = [] {};
+
+ auto captures_nothing_by_value = [=] {};
+ auto captures_nothing_by_reference = [&] {};
+
+ auto implicit_by_value = [=]() mutable { i++; };
+ auto implicit_by_reference = [&] { i++; };
+
+ auto explicit_by_value_used = [i] { return i + 1; };
+ auto explicit_by_value_used_void = [i] { (void)i; };
+ auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
+ auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
+ auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}
+ auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
+
+ auto explicit_by_reference_used = [&i] { i++; };
+ auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}
+
+ auto explicit_initialized_reference_used = [&j = i] { return j + 1; };
+ auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}}
+
+ auto explicit_initialized_value_used = [j = 1] { return j + 1; };
+ auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}}
+ auto explicit_initialized_value_non_trivial_constructor = [j = NonTrivialConstructor()]{};
+ auto explicit_initialized_value_non_trivial_destructor = [j = NonTrivialDestructor()]{};
+ auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}
+ auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
+ auto explicit_initialized_value_with_side_effect = [j = side_effect()]{};
+
+ auto nested = [&i] {
+ auto explicit_by_value_used = [i] { return i + 1; };
+ auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
+ };
+
+ Trivial trivial;
+ auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}}
+
+ NonTrivialConstructor cons;
+ auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}}
+
+ NonTrivialCopyConstructor copy_cons;
+ auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {};
+
+ NonTrivialDestructor dest;
+ auto explicit_by_value_non_trivial_destructor = [dest] {};
+
+ volatile int v;
+ auto explicit_by_value_volatile = [v] {};
+}
+
+void test_use_template() {
+ test_templated<int>(); // expected-note{{in instantiation of function template specialization 'test_templated<int>' requested here}}
+}
diff --git a/test/SemaCXX/warn-unused-value.cpp b/test/SemaCXX/warn-unused-value.cpp
index d6ec0fb5d1cd..98e2a4e86304 100644
--- a/test/SemaCXX/warn-unused-value.cpp
+++ b/test/SemaCXX/warn-unused-value.cpp
@@ -59,11 +59,13 @@ struct Used {
Used();
Used(int);
Used(int, int);
+ ~Used() {}
};
struct __attribute__((warn_unused)) Unused {
Unused();
Unused(int);
Unused(int, int);
+ ~Unused() {}
};
void f() {
Used();
@@ -72,6 +74,10 @@ void f() {
Unused(); // expected-warning {{expression result unused}}
Unused(1); // expected-warning {{expression result unused}}
Unused(1, 1); // expected-warning {{expression result unused}}
+#if __cplusplus >= 201103L // C++11 or later
+ Used({});
+ Unused({}); // expected-warning {{expression result unused}}
+#endif
}
}
diff --git a/test/SemaCXX/zero-length-arrays.cpp b/test/SemaCXX/zero-length-arrays.cpp
index d86ab8666d53..cca883adc4b5 100644
--- a/test/SemaCXX/zero-length-arrays.cpp
+++ b/test/SemaCXX/zero-length-arrays.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// <rdar://problem/10228639>
class Foo {
@@ -12,6 +13,9 @@ public:
class Bar {
int foo_count;
Foo foos[0];
+#if __cplusplus >= 201103L
+// expected-note@-2 {{copy constructor of 'Bar' is implicitly deleted because field 'foos' has an inaccessible copy constructor}}
+#endif
Foo foos2[0][2];
Foo foos3[2][0];
@@ -23,5 +27,10 @@ public:
void testBar() {
Bar b;
Bar b2(b);
+#if __cplusplus >= 201103L
+// expected-error@-2 {{call to implicitly-deleted copy constructor of 'Bar}}
+#else
+// expected-no-diagnostics
+#endif
b = b2;
}
diff --git a/test/SemaObjC/arc-peformselector.m b/test/SemaObjC/arc-peformselector.m
index dec09e33ed68..a7e5d3e8239e 100644
--- a/test/SemaObjC/arc-peformselector.m
+++ b/test/SemaObjC/arc-peformselector.m
@@ -8,6 +8,7 @@
- (id) init __attribute__((ns_returns_not_retained));
- (id)PlusZero;
- (id)PlusOne __attribute__((ns_returns_retained)); // expected-note {{method 'PlusOne' declared here}}
+- (id)self;
@end
@interface I : NSObject
@@ -17,6 +18,9 @@
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
+
+- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(double)delay inModes:(I *)modes;
+
@end
@implementation I
@@ -27,12 +31,20 @@
return [self performSelector : @selector(init)];
return [self performSelector : sel1]; // expected-warning {{performSelector may cause a leak because its selector is unknown}} \
// expected-note {{used here}}
+ return [self performSelector: (@selector(PlusZero))];
return [self performSelector : @selector(PlusZero)];
return [self performSelector : @selector(PlusOne)]; // expected-error {{performSelector names a selector which retains the object}}
+
+ // Avoid the unkown selector warning for more complicated performSelector
+ // variations because it produces too many false positives.
+ [self performSelector: sel1 withObject:0 afterDelay:0 inModes:0];
+
+ return [self performSelector: @selector(self)]; // No error, -self is not +1!
}
- (id)performSelector:(SEL)aSelector { return 0; }
- (id)performSelector:(SEL)aSelector withObject:(id)object { return 0; }
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 { return 0; }
+- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(double)delay inModes:(I *)modes { }
@end
diff --git a/test/SemaObjC/arc-repeated-weak.mm b/test/SemaObjC/arc-repeated-weak.mm
index 11161a0bf7fc..37b2123ec1c4 100644
--- a/test/SemaObjC/arc-repeated-weak.mm
+++ b/test/SemaObjC/arc-repeated-weak.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -Wno-objc-root-class -std=c++11 -Warc-repeated-use-of-weak -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-weak -fblocks -Wno-objc-root-class -std=c++11 -Warc-repeated-use-of-weak -verify %s
@interface Test {
@public
@@ -445,8 +446,8 @@ void doubleLevelAccessIvar(Test *a, Test *b) {
@class NSString;
@interface NSBundle
+(NSBundle *)foo;
-@property (class) NSBundle *foo2;
-@property NSString *prop;
+@property (class, strong) NSBundle *foo2;
+@property (strong) NSString *prop;
@property(weak) NSString *weakProp;
@end
@@ -462,3 +463,19 @@ void foo() {
use(NSBundle.foo2.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
use(NSBundle2.foo2.weakProp); // expected-note{{also accessed here}}
}
+
+// This used to crash in the constructor of WeakObjectProfileTy when a
+// DeclRefExpr was passed that didn't reference a VarDecl.
+
+typedef INTF * INTFPtrTy;
+
+enum E {
+ e1
+};
+
+void foo1() {
+ INTFPtrTy tmp = (INTFPtrTy)e1;
+#if __has_feature(objc_arc)
+// expected-error@-2{{cast of 'E' to 'INTFPtrTy' (aka 'INTF *') is disallowed with ARC}}
+#endif
+}
diff --git a/test/SemaObjC/arc-unavailable-for-weakref.m b/test/SemaObjC/arc-unavailable-for-weakref.m
index 82748027435e..c59616819930 100644
--- a/test/SemaObjC/arc-unavailable-for-weakref.m
+++ b/test/SemaObjC/arc-unavailable-for-weakref.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-weak -verify -Wno-objc-root-class %s
// rdar://9693477
__attribute__((objc_arc_weak_reference_unavailable))
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index f463bb03b075..e90d0a87e311 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wblock-capture-autoreleasing %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -Wno-objc-root-class -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
typedef unsigned long NSUInteger;
typedef const void * CFTypeRef;
@@ -809,9 +810,36 @@ int garf() {
TKAssertEqual(object, (id)nil);
}
-void block_capture_autoreleasing(A * __autoreleasing *a, A **b) { // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+void block_capture_autoreleasing(A * __autoreleasing *a,
+ A **b, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ A * _Nullable *c, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ A * _Nullable __autoreleasing *d,
+ A ** _Nullable e, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ A * __autoreleasing * _Nullable f,
+ id __autoreleasing *g,
+ id *h, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ id _Nullable *i, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ id _Nullable __autoreleasing *j,
+ id * _Nullable k, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}}
+ id __autoreleasing * _Nullable l) {
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-11]]:37-[[@LINE-11]]:37}:" __autoreleasing "
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-11]]:47-[[@LINE-11]]:47}:" __autoreleasing"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:37-[[@LINE-10]]:37}:" __autoreleasing "
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:36-[[@LINE-8]]:36}:" __autoreleasing"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:46-[[@LINE-8]]:46}:" __autoreleasing"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:36-[[@LINE-7]]:36}:" __autoreleasing"
^{
(void)*a;
(void)*b; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*c; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*d;
+ (void)*e; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*f;
+ (void)*g;
+ (void)*h; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*i; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*j;
+ (void)*k; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}}
+ (void)*l;
}();
}
diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m
index 59087bdf1154..b0613851ddaa 100644
--- a/test/SemaObjC/attr-deprecated.m
+++ b/test/SemaObjC/attr-deprecated.m
@@ -83,8 +83,8 @@ int t5() {
}
-__attribute ((deprecated))
-@interface DEPRECATED { // expected-note 2 {{'DEPRECATED' has been explicitly marked deprecated here}}
+__attribute ((deprecated)) // expected-note 2 {{'DEPRECATED' has been explicitly marked deprecated here}}
+@interface DEPRECATED {
@public int ivar;
DEPRECATED *ivar2; // no warning.
}
@@ -121,9 +121,15 @@ void test(Test2 *foo) {
}
__attribute__((deprecated))
-@interface A(Blah) // expected-error{{attributes may not be specified on a category}}
+@interface A(Blah) // no warning
+- (A*)getA;
@end
+@implementation A(Blah) // Don't warn by default
+- (A*)getA {
+ return self;
+}
+@end
typedef struct {
int x;
diff --git a/test/SemaObjC/category-attribute.m b/test/SemaObjC/category-attribute.m
new file mode 100644
index 000000000000..7efe3df00ec8
--- /dev/null
+++ b/test/SemaObjC/category-attribute.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
+// expected-no-diagnostics
+
+__attribute__ ((external_source_symbol(language= "Swift", defined_in="A")))
+@interface TestInterface
+@end
+// CHECK: ObjCInterfaceDecl {{.*}} TestInterface
+// CHECK-NEXT: ExternalSourceSymbolAttr
+
+__attribute__ ((external_source_symbol(language= "Swift", defined_in="B")))
+@interface TestInterface ()
+@end
+// CHECK: ObjCCategoryDecl
+// CHECK-NEXT: ObjCInterface
+// CHECK-NEXT: ExternalSourceSymbolAttr {{.*}} "Swift" "B"
+
+__attribute__ ((external_source_symbol(language= "Swift", defined_in="C")))
+@interface TestInterface (Category)
+@end
+// CHECK: ObjCCategoryDecl
+// CHECK-NEXT: ObjCInterface
+// CHECK-NEXT: ExternalSourceSymbolAttr {{.*}} "Swift" "C"
diff --git a/test/SemaObjC/class-message-protocol-lookup.m b/test/SemaObjC/class-message-protocol-lookup.m
index 37df7a641673..d9f954dc473d 100644
--- a/test/SemaObjC/class-message-protocol-lookup.m
+++ b/test/SemaObjC/class-message-protocol-lookup.m
@@ -32,3 +32,30 @@ int main ()
Class<Test2Protocol> c2 = [c2 alloc]; // ok
return 0;
}
+
+// rdar://22812517
+
+@protocol NSObject
+
+- (int)respondsToSelector:(SEL)aSelector;
+
+@end
+
+__attribute__((objc_root_class))
+@interface NSObject <NSObject>
+
+@end
+
+@protocol OtherProto
+
+- (void)otherInstanceMethod; // expected-note {{method 'otherInstanceMethod' declared here}}
+
+@end
+
+@protocol MyProto <NSObject, OtherProto>
+@end
+
+void allowInstanceMethodsFromRootProtocols(Class<MyProto> c) {
+ [c respondsToSelector: @selector(instanceMethod)]; // no warning
+ [c otherInstanceMethod]; // expected-warning {{instance method 'otherInstanceMethod' found instead of class method 'otherInstanceMethod'}}
+}
diff --git a/test/SemaObjC/default-synthesize-3.m b/test/SemaObjC/default-synthesize-3.m
index dce9edabb90d..fe2b35f61523 100644
--- a/test/SemaObjC/default-synthesize-3.m
+++ b/test/SemaObjC/default-synthesize-3.m
@@ -33,8 +33,8 @@ __attribute ((objc_requires_property_definitions)) // redundant, just for testi
- (id) DeepMustSynthProperty { return 0; }
@end
-__attribute ((objc_requires_property_definitions))
-@interface Deep(CAT) // expected-error {{attributes may not be specified on a category}}
+__attribute ((objc_requires_property_definitions)) // expected-error {{'objc_requires_property_definitions' attribute only applies to Objective-C interfaces}}
+@interface Deep(CAT)
@end
__attribute ((objc_requires_property_definitions)) // expected-error {{'objc_requires_property_definitions' attribute only applies to Objective-C interfaces}}
diff --git a/test/SemaObjC/objc-class-property.m b/test/SemaObjC/objc-class-property.m
index 56285976e194..f8d49112766d 100644
--- a/test/SemaObjC/objc-class-property.m
+++ b/test/SemaObjC/objc-class-property.m
@@ -21,6 +21,8 @@
@property (class) int c2; // expected-note {{property declared here}} \
// expected-note {{property declared here}}
@property (class) int x;
+@property (class, setter=customSet:) int customSetterProperty;
+@property (class, getter=customGet) int customGetterProperty;
@end
@implementation A // expected-warning {{class property 'c2' requires method 'c2' to be defined}} \
@@ -29,6 +31,8 @@
@dynamic (class) x; // refers to the class property
@synthesize z, c2; // expected-error {{@synthesize not allowed on a class property 'c2'}}
@dynamic c; // refers to the class property
+@dynamic customSetterProperty;
+@dynamic customGetterProperty;
@end
int test() {
@@ -37,6 +41,11 @@ int test() {
return a.x + A.c;
}
+void customSelectors() {
+ A.customSetterProperty = 1;
+ (void)A.customGetterProperty;
+}
+
void message_id(id me) {
[me y];
}
diff --git a/test/SemaObjC/property-typecheck-1.m b/test/SemaObjC/property-typecheck-1.m
index 5fb05c8bd384..85e8d4624be1 100644
--- a/test/SemaObjC/property-typecheck-1.m
+++ b/test/SemaObjC/property-typecheck-1.m
@@ -78,6 +78,11 @@ typedef void (F)(void);
- (NSMutableArray*) pieces; // expected-note 2 {{declared here}}
- (NSArray*) first;
+
+// Don't warn about setter-like methods for readonly properties.
+- (void)setFirst:(char)val;
+- (void)setPieces:(char)val;
+
@end
@interface Class2 {
diff --git a/test/SemaObjC/special-dep-unavail-warning.m b/test/SemaObjC/special-dep-unavail-warning.m
index 9e16b331c23c..b667c3c51c9d 100644
--- a/test/SemaObjC/special-dep-unavail-warning.m
+++ b/test/SemaObjC/special-dep-unavail-warning.m
@@ -44,8 +44,8 @@ void test(C *c) {
}
// rdar://10268422
-__attribute ((deprecated))
-@interface DEPRECATED // expected-note {{'DEPRECATED' has been explicitly marked deprecated here}}
+__attribute ((deprecated)) // expected-note {{'DEPRECATED' has been explicitly marked deprecated here}}
+@interface DEPRECATED
+(id)new;
@end
diff --git a/test/SemaObjC/unsafe-perform-selector.m b/test/SemaObjC/unsafe-perform-selector.m
new file mode 100644
index 000000000000..661ff363603f
--- /dev/null
+++ b/test/SemaObjC/unsafe-perform-selector.m
@@ -0,0 +1,127 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
+// rdar://12056271
+
+@class Thread;
+
+__attribute__((objc_root_class))
+@interface NSObject
+
+- (id)performSelector:(SEL)sel;
+- (void)performSelectorInBackground:(SEL)sel withObject:(id)arg;
+- (void)performSelectorOnMainThread:(SEL)sel;
+
+- (void)performSelectorOnMainThread:(SEL)aSelector
+ onThread:(Thread *)thread
+ withObject:(id)arg
+ waitUntilDone:(int)wait
+ modes:(id *)array;
+
+@end
+
+typedef struct { int x; int y; int width; int height; } Rectangle;
+
+struct Struct { Rectangle r; };
+
+typedef union { int x; float f; } Union;
+
+@interface Base : NSObject
+
+- (struct Struct)returnsStruct2; // expected-note {{method 'returnsStruct2' that returns 'struct Struct' declared here}}
+- (Union)returnsId;
+
+@end
+
+@protocol IP
+
+- (Union)returnsUnion; // expected-note 2 {{method 'returnsUnion' that returns 'Union' declared here}}
+
+@end
+
+typedef __attribute__((__ext_vector_type__(3))) float float3;
+typedef int int4 __attribute__ ((vector_size (16)));
+
+@interface I : Base<IP>
+
+- (Rectangle)returnsStruct; // expected-note 4 {{method 'returnsStruct' that returns 'Rectangle' declared here}}
+- (id)returnsId; // shadows base 'returnsId'
+- (int)returnsInt;
+- (I *)returnPtr;
+- (float3)returnsExtVector; // expected-note {{method 'returnsExtVector' that returns 'float3' (vector of 3 'float' values) declared here}}
+- (int4)returnsVector; // expected-note {{method 'returnsVector' that returns 'int4' (vector of 4 'int' values) declared here}}
+
++ (Rectangle)returnsStructClass; // expected-note 2 {{method 'returnsStructClass' that returns 'Rectangle' declared here}}
++ (void)returnsUnion; // Not really
+
+@end
+
+void foo(I *i) {
+ [i performSelector: @selector(returnsStruct)]; // expected-warning {{'performSelector:' is incompatible with selectors that return a struct type}}
+ [i performSelectorInBackground: @selector(returnsStruct) withObject:0]; // expected-warning {{'performSelectorInBackground:withObject:' is incompatible with selectors that return a struct type}}
+ [i performSelector: ((@selector(returnsUnion)))]; // expected-warning {{'performSelector:' is incompatible with selectors that return a union type}}
+ [i performSelectorOnMainThread: @selector(returnsStruct2)]; // expected-warning {{'performSelectorOnMainThread:' is incompatible with selectors that return a struct type}}
+ [I performSelector: (@selector(returnsStructClass))]; // expected-warning {{'performSelector:' is incompatible with selectors that return a struct type}}
+
+ [i performSelector: @selector(returnsId)];
+ [i performSelector: @selector(returnsInt)];
+ [i performSelector: @selector(returnsPtr)];
+ [I performSelector: @selector(returnsUnion)]; // No warning expected
+
+ id obj = i;
+ [obj performSelector: @selector(returnsId)];
+ [obj performSelector: @selector(returnsStruct)];
+}
+
+@interface SubClass: I
+
+@end
+
+@interface SubClass ()
+- (struct Struct)returnsSubStructExt; // expected-note {{method 'returnsSubStructExt' that returns 'struct Struct' declared here}} expected-note {{method 'returnsSubStructExt' declared here}}
+@end
+
+@implementation SubClass // expected-warning {{method definition for 'returnsSubStructExt' not found}}
+
+- (struct Struct)returnsSubStructImpl { // expected-note {{method 'returnsSubStructImpl' that returns 'struct Struct' declared here}}
+ struct Struct Result;
+ return Result;
+}
+
+- (void)checkPrivateCalls {
+ [self performSelector: @selector(returnsSubStructExt)]; // expected-warning {{'performSelector:' is incompatible with selectors that return a struct type}}
+ [self performSelector: @selector(returnsSubStructImpl)]; // expected-warning {{'performSelector:' is incompatible with selectors that return a struct type}}
+}
+
+- (void)checkSuperCalls {
+ [super performSelector: @selector(returnsStruct)]; // expected-warning {{'performSelector:' is incompatible with selectors that return a struct type}}
+ [super performSelectorInBackground: @selector(returnsUnion) withObject: self]; // expected-warning {{'performSelectorInBackground:withObject:' is incompatible with selectors that return a union type}}
+ [super performSelector: @selector(returnsId)];
+}
+
++ (struct Struct)returnsSubStructClassImpl { // expected-note {{method 'returnsSubStructClassImpl' that returns 'struct Struct' declared here}}
+ struct Struct Result;
+ return Result;
+}
+
++ (void)checkClassPrivateCalls {
+ [self performSelector: @selector(returnsSubStructClassImpl)]; // expected-warning {{'performSelector:' is incompatible with selectors that return a struct type}}
+}
+
++ (void)checkClassSuperCalls {
+ [super performSelector: @selector(returnsStructClass)]; // expected-warning {{'performSelector:' is incompatible with selectors that return a struct type}}
+ [super performSelector: @selector(returnsUnion)]; // No warning expected
+}
+
+@end
+
+@implementation I (LongPerformSelectors)
+
+- (void)checkLongCallsFromCategory {
+ [self performSelectorOnMainThread: @selector(returnsStruct) onThread:0 withObject:self waitUntilDone:1 modes:0]; // expected-warning {{'performSelectorOnMainThread:onThread:withObject:waitUntilDone:modes:' is incompatible with selectors that return a struct type}}
+}
+
+- (void)checkVectorReturn {
+ [self performSelector: @selector(returnsExtVector)]; // expected-warning {{'performSelector:' is incompatible with selectors that return a vector type}}
+ [self performSelector: @selector(returnsVector)]; // expected-warning {{'performSelector:' is incompatible with selectors that return a vector type}}
+}
+
+@end
diff --git a/test/SemaObjC/warn-deprecated-implementations.m b/test/SemaObjC/warn-deprecated-implementations.m
index 6e208b5be795..0c341165b0f0 100644
--- a/test/SemaObjC/warn-deprecated-implementations.m
+++ b/test/SemaObjC/warn-deprecated-implementations.m
@@ -28,8 +28,8 @@
- (void) G {} // No warning, implementing its own deprecated method
@end
-__attribute__((deprecated))
-@interface CL // expected-note 2 {{class declared here}} // expected-note 2 {{'CL' has been explicitly marked deprecated here}}
+__attribute__((deprecated)) // expected-note 2 {{'CL' has been explicitly marked deprecated here}}
+@interface CL // expected-note 2 {{class declared here}}
@end
@implementation CL // expected-warning {{Implementing deprecated class}}
@@ -65,3 +65,10 @@ __attribute__((deprecated))
return (void *)0;
}
@end
+
+__attribute__((deprecated))
+@interface Test(DeprecatedCategory) // expected-note {{category declared here}}
+@end
+
+@implementation Test(DeprecatedCategory) // expected-warning {{Implementing deprecated category}}
+@end
diff --git a/test/SemaObjCXX/arc-bridged-cast.mm b/test/SemaObjCXX/arc-bridged-cast.mm
index 55cdd3f2c482..b5d57740eec0 100644
--- a/test/SemaObjCXX/arc-bridged-cast.mm
+++ b/test/SemaObjCXX/arc-bridged-cast.mm
@@ -52,3 +52,19 @@ void testObjCBridgeId() {
ref = (__bridge_retained CFAnnotatedObjectRef) CreateSomething();
ref = (__bridge_retained CFAnnotatedObjectRef) CreateNSString();
}
+
+struct __CFAnnotatedObject {
+} cf0;
+
+extern const CFAnnotatedObjectRef r0;
+extern const CFAnnotatedObjectRef r1 = &cf0;
+extern "C" const CFAnnotatedObjectRef r2;
+extern "C" const CFAnnotatedObjectRef r3 = &cf0;
+
+void testExternC() {
+ id obj;
+ obj = (id)r0;
+ obj = (id)r1; // expected-error{{cast of C pointer type 'CFAnnotatedObjectRef' (aka 'const __CFAnnotatedObject *') to Objective-C pointer type 'id' requires a bridged cast}} expected-note{{use __bridge to convert directly}} expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFAnnotatedObjectRef'}}
+ obj = (id)r2;
+ obj = (id)r3; // expected-error{{cast of C pointer type 'CFAnnotatedObjectRef' (aka 'const __CFAnnotatedObject *') to Objective-C pointer type 'id' requires a bridged cast}} expected-note{{use __bridge to convert directly}} expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFAnnotatedObjectRef'}}
+}
diff --git a/test/SemaObjCXX/arc-ptr-comparison.mm b/test/SemaObjCXX/arc-ptr-comparison.mm
new file mode 100644
index 000000000000..8571a8179598
--- /dev/null
+++ b/test/SemaObjCXX/arc-ptr-comparison.mm
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin11 -fsyntax-only -verify -DNOARC %s
+#ifdef NOARC
+// expected-no-diagnostics
+#endif
+
+int testObjCComparisonRules(void *v, id x, id y) {
+ return v == x;
+#ifndef NOARC
+// expected-error@-2 {{implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}}
+// expected-note@-3 {{use __bridge to convert directly (no change in ownership)}}
+// expected-note@-4 {{use __bridge_retained to make an ARC object available as a +1 'void *'}}
+#endif
+ return v >= x;
+#ifndef NOARC
+// expected-error@-2 {{implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}}
+// expected-note@-3 {{use __bridge to convert directly (no change in ownership)}}
+// expected-note@-4 {{use __bridge_retained to make an ARC object available as a +1 'void *'}}
+#endif
+ return v == (id)(void *)0; // OK
+ return v == nullptr; // OK
+ return v == (void *)0;
+ return x == y;
+}
diff --git a/test/SemaObjCXX/arc-system-header.mm b/test/SemaObjCXX/arc-system-header.mm
index 5f5445c8956b..00ffad7ced4d 100644
--- a/test/SemaObjCXX/arc-system-header.mm
+++ b/test/SemaObjCXX/arc-system-header.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-arc -isystem %S/Inputs %s -verify
+// RUN: %clang_cc1 -std=gnu++98 -fobjc-arc -isystem %S/Inputs %s -verify
#include <arc-system-header.h>
diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm
index 97854dff8c1a..2a7d11f9d1f9 100644
--- a/test/SemaObjCXX/arc-templates.mm
+++ b/test/SemaObjCXX/arc-templates.mm
@@ -102,8 +102,8 @@ int check_make_weak2[is_same<make_weak<__autoreleasing id>::type, __weak id>::va
template<typename T>
struct make_weak_fail {
typedef T T_type;
- typedef __weak T_type type; // expected-error{{the type 'T_type' (aka '__weak id') is already explicitly ownership-qualified}} \
- // expected-error{{the type 'T_type' (aka '__strong id') is already explicitly ownership-qualified}}
+ typedef __weak T_type type; // expected-error{{the type 'make_weak_fail<__weak id>::T_type' (aka '__weak id') is already explicitly ownership-qualified}} \
+ // expected-error{{the type 'make_weak_fail<id>::T_type' (aka '__strong id') is already explicitly ownership-qualified}}
};
int check_make_weak_fail0[is_same<make_weak_fail<__weak id>::type, __weak id>::value? 1 : -1]; // expected-note{{in instantiation of template class 'make_weak_fail<__weak id>' requested here}}
diff --git a/test/SemaObjCXX/arc-unavailable-for-weakref.mm b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
index 2a80aebaf8e5..6528748df393 100644
--- a/test/SemaObjCXX/arc-unavailable-for-weakref.mm
+++ b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-weak -verify %s
// rdar://9693477
__attribute__((objc_arc_weak_reference_unavailable))
diff --git a/test/SemaObjCXX/blocks.mm b/test/SemaObjCXX/blocks.mm
index 3f901cc0a840..bdd5538e92be 100644
--- a/test/SemaObjCXX/blocks.mm
+++ b/test/SemaObjCXX/blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class -std=c++14 %s
@protocol NSObject;
void bar(id(^)(void));
@@ -145,6 +145,17 @@ namespace DependentReturn {
template void f<X>(X);
}
+namespace GenericLambdaCapture {
+int test(int outerp) {
+ auto lambda =[&](auto p) {
+ return ^{
+ return p + outerp;
+ }();
+ };
+ return lambda(1);
+}
+}
+
namespace MoveBlockVariable {
struct B0 {
};
diff --git a/test/SemaObjCXX/ivar-construct.mm b/test/SemaObjCXX/ivar-construct.mm
index 473c0bf4b02d..1498275b0b98 100644
--- a/test/SemaObjCXX/ivar-construct.mm
+++ b/test/SemaObjCXX/ivar-construct.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -std=gnu++98 -fsyntax-only -verify -Wno-objc-root-class %s
struct Y {
Y();
diff --git a/test/SemaObjCXX/objc-weak-type-traits.mm b/test/SemaObjCXX/objc-weak-type-traits.mm
new file mode 100644
index 000000000000..f425f47bd6fd
--- /dev/null
+++ b/test/SemaObjCXX/objc-weak-type-traits.mm
@@ -0,0 +1,210 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-weak -fobjc-runtime-has-weak -verify -std=c++11 %s
+// expected-no-diagnostics
+
+// Check the results of the various type-trait query functions on
+// lifetime-qualified types in ObjC Weak.
+
+#define TRAIT_IS_TRUE(Trait, Type) static_assert(Trait(Type), "")
+#define TRAIT_IS_FALSE(Trait, Type) static_assert(!Trait(Type), "")
+#define TRAIT_IS_TRUE_2(Trait, Type1, Type2) static_assert(Trait(Type1, Type2), "")
+#define TRAIT_IS_FALSE_2(Trait, Type1, Type2) static_assert(!Trait(Type1, Type2), "")
+
+struct HasStrong { id obj; };
+struct HasWeak { __weak id obj; };
+struct HasUnsafeUnretained { __unsafe_unretained id obj; };
+
+// __has_nothrow_assign
+TRAIT_IS_TRUE(__has_nothrow_assign, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __unsafe_unretained id);
+TRAIT_IS_TRUE(__has_nothrow_assign, HasStrong);
+TRAIT_IS_TRUE(__has_nothrow_assign, HasWeak);
+TRAIT_IS_TRUE(__has_nothrow_assign, HasUnsafeUnretained);
+
+// __has_nothrow_copy
+TRAIT_IS_TRUE(__has_nothrow_copy, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __unsafe_unretained id);
+TRAIT_IS_TRUE(__has_nothrow_copy, HasStrong);
+TRAIT_IS_TRUE(__has_nothrow_copy, HasWeak);
+TRAIT_IS_TRUE(__has_nothrow_copy, HasUnsafeUnretained);
+
+// __has_nothrow_constructor
+TRAIT_IS_TRUE(__has_nothrow_constructor, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __unsafe_unretained id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, HasStrong);
+TRAIT_IS_TRUE(__has_nothrow_constructor, HasWeak);
+TRAIT_IS_TRUE(__has_nothrow_constructor, HasUnsafeUnretained);
+
+// __has_trivial_assign
+TRAIT_IS_TRUE(__has_trivial_assign, __strong id);
+TRAIT_IS_FALSE(__has_trivial_assign, __weak id);
+TRAIT_IS_TRUE(__has_trivial_assign, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_assign, __unsafe_unretained id);
+TRAIT_IS_TRUE(__has_trivial_assign, HasStrong);
+TRAIT_IS_FALSE(__has_trivial_assign, HasWeak);
+TRAIT_IS_TRUE(__has_trivial_assign, HasUnsafeUnretained);
+
+// __has_trivial_copy
+TRAIT_IS_TRUE(__has_trivial_copy, __strong id);
+TRAIT_IS_FALSE(__has_trivial_copy, __weak id);
+TRAIT_IS_TRUE(__has_trivial_copy, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_copy, __unsafe_unretained id);
+TRAIT_IS_TRUE(__has_trivial_copy, HasStrong);
+TRAIT_IS_FALSE(__has_trivial_copy, HasWeak);
+TRAIT_IS_TRUE(__has_trivial_copy, HasUnsafeUnretained);
+
+// __has_trivial_constructor
+TRAIT_IS_TRUE(__has_trivial_constructor, __strong id);
+TRAIT_IS_FALSE(__has_trivial_constructor, __weak id);
+TRAIT_IS_TRUE(__has_trivial_constructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_constructor, __unsafe_unretained id);
+TRAIT_IS_TRUE(__has_trivial_constructor, HasStrong);
+TRAIT_IS_FALSE(__has_trivial_constructor, HasWeak);
+TRAIT_IS_TRUE(__has_trivial_constructor, HasUnsafeUnretained);
+
+// __has_trivial_destructor
+TRAIT_IS_TRUE(__has_trivial_destructor, __strong id);
+TRAIT_IS_FALSE(__has_trivial_destructor, __weak id);
+TRAIT_IS_TRUE(__has_trivial_destructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_destructor, __unsafe_unretained id);
+TRAIT_IS_TRUE(__has_trivial_destructor, HasStrong);
+TRAIT_IS_FALSE(__has_trivial_destructor, HasWeak);
+TRAIT_IS_TRUE(__has_trivial_destructor, HasUnsafeUnretained);
+
+// __is_literal
+TRAIT_IS_TRUE(__is_literal, __strong id);
+TRAIT_IS_TRUE(__is_literal, __weak id);
+TRAIT_IS_TRUE(__is_literal, __autoreleasing id);
+TRAIT_IS_TRUE(__is_literal, __unsafe_unretained id);
+
+// __is_literal_type
+TRAIT_IS_TRUE(__is_literal_type, __strong id);
+TRAIT_IS_TRUE(__is_literal_type, __weak id);
+TRAIT_IS_TRUE(__is_literal_type, __autoreleasing id);
+TRAIT_IS_TRUE(__is_literal_type, __unsafe_unretained id);
+
+// __is_pod
+TRAIT_IS_TRUE(__is_pod, __strong id);
+TRAIT_IS_FALSE(__is_pod, __weak id);
+TRAIT_IS_TRUE(__is_pod, __autoreleasing id);
+TRAIT_IS_TRUE(__is_pod, __unsafe_unretained id);
+TRAIT_IS_TRUE(__is_pod, HasStrong);
+TRAIT_IS_FALSE(__is_pod, HasWeak);
+TRAIT_IS_TRUE(__is_pod, HasUnsafeUnretained);
+
+// __is_trivial
+TRAIT_IS_TRUE(__is_trivial, __strong id);
+TRAIT_IS_FALSE(__is_trivial, __weak id);
+TRAIT_IS_TRUE(__is_trivial, __autoreleasing id);
+TRAIT_IS_TRUE(__is_trivial, __unsafe_unretained id);
+TRAIT_IS_TRUE(__is_trivial, HasStrong);
+TRAIT_IS_FALSE(__is_trivial, HasWeak);
+TRAIT_IS_TRUE(__is_trivial, HasUnsafeUnretained);
+
+// __is_scalar
+TRAIT_IS_TRUE(__is_scalar, __strong id);
+TRAIT_IS_FALSE(__is_scalar, __weak id);
+TRAIT_IS_TRUE(__is_scalar, __autoreleasing id);
+TRAIT_IS_TRUE(__is_scalar, __unsafe_unretained id);
+
+// __is_standard_layout
+TRAIT_IS_TRUE(__is_standard_layout, __strong id);
+TRAIT_IS_TRUE(__is_standard_layout, __weak id);
+TRAIT_IS_TRUE(__is_standard_layout, __autoreleasing id);
+TRAIT_IS_TRUE(__is_standard_layout, __unsafe_unretained id);
+
+// __is_trivally_assignable
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __strong id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __weak id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __autoreleasing id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __unsafe_unretained id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __strong id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __weak id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __autoreleasing id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __unsafe_unretained id&&);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __strong id);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __weak id);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __autoreleasing id);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __unsafe_unretained id);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __strong id&&);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __weak id&&);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __autoreleasing id&&);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __unsafe_unretained id&&);
+
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __strong id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __weak id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __autoreleasing id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __unsafe_unretained id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __strong id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __weak id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __autoreleasing id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __unsafe_unretained id&&);
+
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __strong id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __weak id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __autoreleasing id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __unsafe_unretained id);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __strong id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __weak id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __autoreleasing id&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __unsafe_unretained id&&);
+
+TRAIT_IS_TRUE_2(__is_trivially_assignable, HasStrong&, HasStrong);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, HasStrong&, HasStrong&&);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, HasWeak&, HasWeak);
+TRAIT_IS_FALSE_2(__is_trivially_assignable, HasWeak&, HasWeak&&);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, HasUnsafeUnretained&, HasUnsafeUnretained);
+TRAIT_IS_TRUE_2(__is_trivially_assignable, HasUnsafeUnretained&, HasUnsafeUnretained&&);
+
+// __is_trivally_constructible
+TRAIT_IS_TRUE(__is_trivially_constructible, __strong id);
+TRAIT_IS_FALSE(__is_trivially_constructible, __weak id);
+TRAIT_IS_TRUE(__is_trivially_constructible, __autoreleasing id);
+TRAIT_IS_TRUE(__is_trivially_constructible, __unsafe_unretained id);
+
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __strong id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __weak id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __autoreleasing id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __unsafe_unretained id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __strong id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __weak id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __autoreleasing id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __unsafe_unretained id&&);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __strong id);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __weak id);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __autoreleasing id);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __unsafe_unretained id);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __strong id&&);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __weak id&&);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __autoreleasing id&&);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __unsafe_unretained id&&);
+
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __strong id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __weak id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __autoreleasing id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __unsafe_unretained id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __strong id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __weak id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __autoreleasing id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __unsafe_unretained id&&);
+
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __strong id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __weak id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __autoreleasing id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __unsafe_unretained id);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __strong id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __weak id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __autoreleasing id&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __unsafe_unretained id&&);
+
+TRAIT_IS_TRUE_2(__is_trivially_constructible, HasStrong, HasStrong);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, HasStrong, HasStrong&&);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, HasWeak, HasWeak);
+TRAIT_IS_FALSE_2(__is_trivially_constructible, HasWeak, HasWeak&&);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, HasUnsafeUnretained, HasUnsafeUnretained);
+TRAIT_IS_TRUE_2(__is_trivially_constructible, HasUnsafeUnretained, HasUnsafeUnretained&&);
diff --git a/test/SemaObjCXX/objc-weak.mm b/test/SemaObjCXX/objc-weak.mm
new file mode 100644
index 000000000000..93c6af1aa3ec
--- /dev/null
+++ b/test/SemaObjCXX/objc-weak.mm
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-weak -fblocks -Wno-objc-root-class -std=c++98 -Wno-c++0x-extensions -verify %s
+
+@interface AnObject
+@property(weak) id value;
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface NOWEAK : AnObject // expected-note 2 {{class is declared here}}
+@end
+
+struct S {
+ __weak id a; // expected-note {{because type 'S' has a member with __weak ownership}}
+};
+
+union U {
+ __weak id a; // expected-error {{ARC forbids Objective-C objects in union}}
+ S b; // expected-error {{union member 'b' has a non-trivial copy constructor}}
+};
+
+void testCast(AnObject *o) {
+ __weak id a = reinterpret_cast<__weak NOWEAK *>(o); // expected-error {{class is incompatible with __weak references}} \
+ // expected-error {{explicit ownership qualifier on cast result has no effect}} \
+ // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+
+ __weak id b = static_cast<__weak NOWEAK *>(o); // expected-error {{class is incompatible with __weak references}} \
+ // expected-error {{explicit ownership qualifier on cast result has no effect}} \
+ // expected-error {{assignment of a weak-unavailable object to a __weak object}}
+}
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
index bb94d9ed92c3..018afc9b4292 100644
--- a/test/SemaObjCXX/overload.mm
+++ b/test/SemaObjCXX/overload.mm
@@ -174,3 +174,30 @@ namespace class_id {
void f(Class) { }
void f(id) { }
}
+
+@interface NSDictionary<__covariant KeyType, __covariant ObjectType> : A
+@end
+
+@interface NSMutableDictionary<KeyType, ObjectType> : NSDictionary<KeyType, ObjectType>
+@end
+
+namespace rdar20124827 {
+
+int overload(NSDictionary *) { return 1; }
+
+__attribute__((deprecated)) // expected-note {{'overload' has been explicitly marked deprecated here}}
+int overload(NSMutableDictionary *) { return 0; }
+
+__attribute__((deprecated))
+void overload2(NSDictionary *); // expected-note {{candidate function}}
+void overload2(NSDictionary<A *, A *> *); // expected-note {{candidate function}}
+
+void test(NSDictionary *d1, NSDictionary<A *, A *> *d2, NSMutableDictionary<A *, A *> *m1) {
+ overload(d1);
+ overload(d2); // no warning
+ overload(m1); // expected-warning {{'overload' is deprecated}}
+ overload2(d2); // no warning
+ overload2(m1); // expected-error {{call to 'overload2' is ambiguous}}
+}
+
+}
diff --git a/test/SemaOpenCL/access-qualifier.cl b/test/SemaOpenCL/access-qualifier.cl
index 7bc974109f3c..35e838b1bf83 100644
--- a/test/SemaOpenCL/access-qualifier.cl
+++ b/test/SemaOpenCL/access-qualifier.cl
@@ -74,3 +74,7 @@ kernel void k14(read_only pipe int p) {
myPipeWrite(p); // expected-error {{passing 'read_only pipe int' to parameter of incompatible type 'write_only pipe int'}}
}
#endif
+
+#if __OPENCL_C_VERSION__ < 200
+kernel void test_image3d_wo(write_only image3d_t img) {} // expected-error {{use of type '__write_only image3d_t' requires cl_khr_3d_image_writes extension to be enabled}}
+#endif
diff --git a/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl b/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
index 97fd07a24a24..73e29e7879d5 100644
--- a/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
+++ b/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
@@ -18,14 +18,20 @@
#ifdef GENERIC
#define AS generic
+#define AS_COMP local
+#define AS_INCOMP constant
#endif
#ifdef GLOBAL
#define AS global
+#define AS_COMP global
+#define AS_INCOMP local
#endif
#ifdef CONSTANT
#define AS constant
+#define AS_COMP constant
+#define AS_INCOMP global
#endif
void f_glob(global int *arg_glob) {}
@@ -263,12 +269,16 @@ void test_ternary() {
var_void_gen = 0 ? var_cond : var_glob_ch;
#ifdef CONSTANT
// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__global char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning-re@-4{{pointer type mismatch ('__{{global|generic}} int *' and '__global char *')}}
#endif
local char *var_loc_ch;
var_void_gen = 0 ? var_cond : var_loc_ch;
#ifndef GENERIC
// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and '__local char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning@-4{{pointer type mismatch ('__generic int *' and '__local char *')}}
#endif
constant void *var_void_const;
@@ -276,18 +286,45 @@ void test_ternary() {
var_void_const = 0 ? var_cond : var_const_ch;
#ifndef CONSTANT
// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|generic}} int *' and '__constant char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning@-4{{pointer type mismatch ('__constant int *' and '__constant char *')}}
#endif
private char *var_priv_ch;
var_void_gen = 0 ? var_cond : var_priv_ch;
#ifndef GENERIC
// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and 'char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning@-4{{pointer type mismatch ('__generic int *' and 'char *')}}
#endif
generic char *var_gen_ch;
var_void_gen = 0 ? var_cond : var_gen_ch;
#ifdef CONSTANT
// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__generic char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning-re@-4{{pointer type mismatch ('__{{global|generic}} int *' and '__generic char *')}}
#endif
}
+void test_pointer_chains() {
+ AS int *AS *var_as_as_int;
+ AS int *AS_COMP *var_asc_as_int;
+ AS_INCOMP int *AS_COMP *var_asc_asn_int;
+ AS_COMP int *AS_COMP *var_asc_asc_int;
+
+ // Case 1:
+ // * address spaces of corresponded most outer pointees overlaps, their canonical types are equal
+ // * CVR, address spaces and canonical types of the rest of pointees are equivalent.
+ var_as_as_int = 0 ? var_as_as_int : var_asc_as_int;
+
+ // Case 2: Corresponded inner pointees has non-overlapping address spaces.
+ var_as_as_int = 0 ? var_as_as_int : var_asc_asn_int;
+// expected-warning-re@-1{{pointer type mismatch ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *' and '__{{(local|global|constant)}} int *__{{(constant|local|global)}} *')}}
+
+ // Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces.
+#ifdef GENERIC
+ var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int;
+// expected-warning-re@-1{{pointer type mismatch ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *' and '__{{(local|global|constant)}} int *__{{(local|global|constant)}} *')}}
+#endif
+}
diff --git a/test/SemaOpenCL/as_type.cl b/test/SemaOpenCL/as_type.cl
index f0bf4d7daef2..ad418097d902 100644
--- a/test/SemaOpenCL/as_type.cl
+++ b/test/SemaOpenCL/as_type.cl
@@ -1,7 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -o - -verify -fsyntax-only
-
-typedef __attribute__(( ext_vector_type(3) )) char char3;
-typedef __attribute__(( ext_vector_type(16) )) char char16;
+// RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -finclude-default-header -o - -verify -fsyntax-only
char3 f1(char16 x) {
return __builtin_astype(x, char3); // expected-error{{invalid reinterpretation: sizes of 'char3' (vector of 3 'char' values) and 'char16' (vector of 16 'char' values) must match}}
@@ -11,3 +8,7 @@ char16 f3(int x) {
return __builtin_astype(x, char16); // expected-error{{invalid reinterpretation: sizes of 'char16' (vector of 16 'char' values) and 'int' must match}}
}
+void foo() {
+ char src = 1;
+ int dst = as_int(src); // expected-error{{invalid reinterpretation: sizes of 'int' and 'char' must match}}
+}
diff --git a/test/SemaOpenCL/atomic-init.cl b/test/SemaOpenCL/atomic-init.cl
new file mode 100644
index 000000000000..8208a85c3dab
--- /dev/null
+++ b/test/SemaOpenCL/atomic-init.cl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -O0 -cl-std=CL2.0 -fsyntax-only -verify %s
+
+global atomic_int a1 = 0;
+
+kernel void test_atomic_initialization() {
+ a1 = 1; // expected-error {{atomic variable can be assigned to a variable only in global address space}}
+ atomic_int a2 = 0; // expected-error {{atomic variable can be initialized to a variable only in global address space}}
+ private atomic_int a3 = 0; // expected-error {{atomic variable can be initialized to a variable only in global address space}}
+ local atomic_int a4 = 0; // expected-error {{'__local' variable cannot have an initializer}}
+ global atomic_int a5 = 0; // expected-error {{function scope variable cannot be declared in global address space}}
+ static global atomic_int a6 = 0;
+}
diff --git a/test/SemaOpenCL/builtins-amdgcn-error-f16.cl b/test/SemaOpenCL/builtins-amdgcn-error-f16.cl
index 7fa47179cb71..3487b1a5a803 100644
--- a/test/SemaOpenCL/builtins-amdgcn-error-f16.cl
+++ b/test/SemaOpenCL/builtins-amdgcn-error-f16.cl
@@ -1,9 +1,10 @@
// REQUIRES: amdgpu-registered-target
-// RUN: %clang_cc1 -triple amdgcn-- -target-cpu tahiti -verify -S -o - %s
+// RUN: %clang_cc1 -triple amdgcn-- -verify -S -o - %s
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
-void test_f16(global half *out, half a, half b, half c)
+__attribute__((target("arch=tahiti")))
+void test_f16_tahiti(global half *out, half a, half b, half c)
{
*out = __builtin_amdgcn_div_fixuph(a, b, c); // expected-error {{'__builtin_amdgcn_div_fixuph' needs target feature 16-bit-insts}}
*out = __builtin_amdgcn_rcph(a); // expected-error {{'__builtin_amdgcn_rcph' needs target feature 16-bit-insts}}
@@ -15,4 +16,5 @@ void test_f16(global half *out, half a, half b, half c)
*out = __builtin_amdgcn_frexp_exph(a); // expected-error {{'__builtin_amdgcn_frexp_exph' needs target feature 16-bit-insts}}
*out = __builtin_amdgcn_fracth(a); // expected-error {{'__builtin_amdgcn_fracth' needs target feature 16-bit-insts}}
*out = __builtin_amdgcn_classh(a, b); // expected-error {{'__builtin_amdgcn_classh' needs target feature 16-bit-insts}}
+ *out = __builtin_amdgcn_fmed3h(a, b, c); // expected-error {{'__builtin_amdgcn_fmed3h' needs target feature gfx9-insts}}
}
diff --git a/test/SemaOpenCL/builtins-amdgcn-error-gfx9.cl b/test/SemaOpenCL/builtins-amdgcn-error-gfx9.cl
new file mode 100644
index 000000000000..c9fd8ab2cae8
--- /dev/null
+++ b/test/SemaOpenCL/builtins-amdgcn-error-gfx9.cl
@@ -0,0 +1,9 @@
+// REQUIRES: amdgpu-registered-target
+// RUN: %clang_cc1 -triple amdgcn-- -target-cpu fiji -verify -S -o - %s
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+void test_gfx9_fmed3h(global half *out, half a, half b, half c)
+{
+ *out = __builtin_amdgcn_fmed3h(a, b, c); // expected-error {{'__builtin_amdgcn_fmed3h' needs target feature gfx9-insts}}
+}
diff --git a/test/SemaOpenCL/builtins-amdgcn-error.cl b/test/SemaOpenCL/builtins-amdgcn-error.cl
index 83ccbefddc6f..2639bf27752f 100644
--- a/test/SemaOpenCL/builtins-amdgcn-error.cl
+++ b/test/SemaOpenCL/builtins-amdgcn-error.cl
@@ -1,16 +1,17 @@
// REQUIRES: amdgpu-registered-target
// RUN: %clang_cc1 -triple amdgcn-- -target-cpu tahiti -verify -S -o - %s
-// FIXME: We only get one error if the functions are the other order in the
-// file.
-
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
typedef unsigned long ulong;
typedef unsigned int uint;
-ulong test_s_memrealtime()
+// To get all errors for feature checking we need to put them in one function
+// since Clang will stop codegen for the next function if it finds error during
+// codegen of the previous function.
+void test_target_builtin(global int* out, int a)
{
- return __builtin_amdgcn_s_memrealtime(); // expected-error {{'__builtin_amdgcn_s_memrealtime' needs target feature s-memrealtime}}
+ __builtin_amdgcn_s_memrealtime(); // expected-error {{'__builtin_amdgcn_s_memrealtime' needs target feature s-memrealtime}}
+ *out = __builtin_amdgcn_mov_dpp(a, 0, 0, 0, false); // expected-error {{'__builtin_amdgcn_mov_dpp' needs target feature dpp}}
}
void test_s_sleep(int x)
@@ -18,6 +19,31 @@ void test_s_sleep(int x)
__builtin_amdgcn_s_sleep(x); // expected-error {{argument to '__builtin_amdgcn_s_sleep' must be a constant integer}}
}
+void test_s_waitcnt(int x)
+{
+ __builtin_amdgcn_s_waitcnt(x); // expected-error {{argument to '__builtin_amdgcn_s_waitcnt' must be a constant integer}}
+}
+
+void test_s_sendmsg(int in)
+{
+ __builtin_amdgcn_s_sendmsg(in, 1); // expected-error {{argument to '__builtin_amdgcn_s_sendmsg' must be a constant integer}}
+}
+
+void test_s_sendmsg_var(int in1, int in2)
+{
+ __builtin_amdgcn_s_sendmsg(in1, in2); // expected-error {{argument to '__builtin_amdgcn_s_sendmsg' must be a constant integer}}
+}
+
+void test_s_sendmsghalt(int in)
+{
+ __builtin_amdgcn_s_sendmsghalt(in, 1); // expected-error {{argument to '__builtin_amdgcn_s_sendmsghalt' must be a constant integer}}
+}
+
+void test_s_sendmsghalt_var(int in1, int in2)
+{
+ __builtin_amdgcn_s_sendmsghalt(in1, in2); // expected-error {{argument to '__builtin_amdgcn_s_sendmsghalt' must be a constant integer}}
+}
+
void test_s_incperflevel(int x)
{
__builtin_amdgcn_s_incperflevel(x); // expected-error {{argument to '__builtin_amdgcn_s_incperflevel' must be a constant integer}}
@@ -62,3 +88,17 @@ void test_ds_swizzle(global int* out, int a, int b)
{
*out = __builtin_amdgcn_ds_swizzle(a, b); // expected-error {{argument to '__builtin_amdgcn_ds_swizzle' must be a constant integer}}
}
+
+void test_s_getreg(global int* out, int a)
+{
+ *out = __builtin_amdgcn_s_getreg(a); // expected-error {{argument to '__builtin_amdgcn_s_getreg' must be a constant integer}}
+}
+
+void test_mov_dpp2(global int* out, int a, int b, int c, int d, bool e)
+{
+ *out = __builtin_amdgcn_mov_dpp(a, b, 0, 0, false); // expected-error {{argument to '__builtin_amdgcn_mov_dpp' must be a constant integer}}
+ *out = __builtin_amdgcn_mov_dpp(a, 0, c, 0, false); // expected-error {{argument to '__builtin_amdgcn_mov_dpp' must be a constant integer}}
+ *out = __builtin_amdgcn_mov_dpp(a, 0, 0, d, false); // expected-error {{argument to '__builtin_amdgcn_mov_dpp' must be a constant integer}}
+ *out = __builtin_amdgcn_mov_dpp(a, 0, 0, 0, e); // expected-error {{argument to '__builtin_amdgcn_mov_dpp' must be a constant integer}}
+}
+
diff --git a/test/SemaOpenCL/cl20-device-side-enqueue.cl b/test/SemaOpenCL/cl20-device-side-enqueue.cl
index c98145c2c900..3e87cfcddf66 100644
--- a/test/SemaOpenCL/cl20-device-side-enqueue.cl
+++ b/test/SemaOpenCL/cl20-device-side-enqueue.cl
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 %s -cl-std=CL2.0 -triple "spir-unknown-unknown" -verify -pedantic -fsyntax-only -DB32
// RUN: %clang_cc1 %s -cl-std=CL2.0 -triple "spir64-unknown-unknown" -verify -pedantic -fsyntax-only -Wconversion -DWCONV
+typedef struct {int a;} ndrange_t;
// Diagnostic tests for different overloads of enqueue_kernel from Table 6.13.17.1 of OpenCL 2.0 Spec.
kernel void enqueue_kernel_tests() {
queue_t default_queue;
@@ -30,7 +31,7 @@ kernel void enqueue_kernel_tests() {
enqueue_kernel(default_queue, flags, ndrange, vptr); // expected-error{{illegal call to enqueue_kernel, expected block argument}}
- enqueue_kernel(default_queue, flags, ndrange, ^(int i) { // expected-error{{blocks in this form of device side enqueue call are expected to have have no parameters}}
+ enqueue_kernel(default_queue, flags, ndrange, ^(int i) { // expected-error{{blocks with parameters are not accepted in this prototype of enqueue_kernel call}}
return 0;
});
@@ -111,7 +112,7 @@ kernel void enqueue_kernel_tests() {
const bl_B_t block_B = (bl_B_t) ^ (local void *a, local int *b) {};
- enqueue_kernel(default_queue, flags, ndrange, block_B, 1024, 1024); // expected-error{{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
+ enqueue_kernel(default_queue, flags, ndrange, block_B, 1024, 1024); // expected-error{{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
enqueue_kernel(default_queue, flags, ndrange, // expected-error{{mismatch in number of block parameters and local size arguments passed}}
^(local void *a, local void *b) {
@@ -177,12 +178,12 @@ kernel void work_group_size_tests() {
size = get_kernel_work_group_size(^(local void *a) {
return;
});
- size = get_kernel_work_group_size(^(local int *a) { // expected-error {{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
+ size = get_kernel_work_group_size(^(local int *a) { // expected-error {{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
return;
});
- size = get_kernel_work_group_size(block_B); // expected-error {{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
- size = get_kernel_work_group_size(block_D); // expected-error {{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
- size = get_kernel_work_group_size(^(int a) { // expected-error {{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
+ size = get_kernel_work_group_size(block_B); // expected-error {{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
+ size = get_kernel_work_group_size(block_D); // expected-error {{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
+ size = get_kernel_work_group_size(^(int a) { // expected-error {{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
return;
});
size = get_kernel_work_group_size(); // expected-error {{too few arguments to function call, expected 1, have 0}}
@@ -194,14 +195,14 @@ kernel void work_group_size_tests() {
size = get_kernel_preferred_work_group_size_multiple(^(local void *a) {
return;
});
- size = get_kernel_preferred_work_group_size_multiple(^(local int *a) { // expected-error {{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
+ size = get_kernel_preferred_work_group_size_multiple(^(local int *a) { // expected-error {{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
return;
});
- size = get_kernel_preferred_work_group_size_multiple(^(int a) { // expected-error {{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
+ size = get_kernel_preferred_work_group_size_multiple(^(int a) { // expected-error {{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
return;
});
- size = get_kernel_preferred_work_group_size_multiple(block_B); // expected-error {{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
- size = get_kernel_preferred_work_group_size_multiple(block_D); // expected-error {{blocks used in device side enqueue are expected to have parameters of type 'local void*'}}
+ size = get_kernel_preferred_work_group_size_multiple(block_B); // expected-error {{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
+ size = get_kernel_preferred_work_group_size_multiple(block_D); // expected-error {{blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'}}
size = get_kernel_preferred_work_group_size_multiple(); // expected-error {{too few arguments to function call, expected 1, have 0}}
size = get_kernel_preferred_work_group_size_multiple(1); // expected-error{{expected block argument}}
size = get_kernel_preferred_work_group_size_multiple(block_A, 1); // expected-error{{too many arguments to function call, expected 1, have 2}}
diff --git a/test/Sema/invalid-assignment-constant-address-space.c b/test/SemaOpenCL/invalid-assignment-constant-address-space.cl
index 77d6b331c201..32917c493ce3 100644
--- a/test/Sema/invalid-assignment-constant-address-space.c
+++ b/test/SemaOpenCL/invalid-assignment-constant-address-space.cl
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
-#define OPENCL_CONSTANT 8388354
-int __attribute__((address_space(OPENCL_CONSTANT))) c[3] = {0};
+int constant c[3] = {0};
void foo() {
c[0] = 1; //expected-error{{read-only variable is not assignable}}
diff --git a/test/SemaOpenCL/invalid-block.cl b/test/SemaOpenCL/invalid-block.cl
index a9eac1c2b582..89bf03264e13 100644
--- a/test/SemaOpenCL/invalid-block.cl
+++ b/test/SemaOpenCL/invalid-block.cl
@@ -4,26 +4,34 @@
void f0(int (^const bl)());
// All blocks declarations must be const qualified and initialized.
void f1() {
- int (^bl1)() = ^() {return 1;};
- int (^const bl2)() = ^(){return 1;};
+ int (^bl1)(void) = ^() {
+ return 1;
+ };
+ int (^const bl2)(void) = ^() {
+ return 1;
+ };
f0(bl1);
f0(bl2);
- bl1 = bl2; // expected-error{{invalid operands to binary expression ('int (^const)()' and 'int (^const)()')}}
+ bl1 = bl2; // expected-error{{invalid operands to binary expression ('int (__generic ^const)(void)' and 'int (__generic ^const)(void)')}}
int (^const bl3)(); // expected-error{{invalid block variable declaration - must be initialized}}
}
// A block with extern storage class is not allowed.
-extern int (^bl)() = ^(){return 1;}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}}
+extern int (^bl)(void) = ^() { // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}}
+ return 1;
+};
void f2() {
- extern int (^bl)() = ^(){return 1;}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}}
+ extern int (^bl)(void) = ^() { // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}}
+ return 1;
+ };
}
// A block cannot be the return value of a function.
typedef int (^bl_t)(void);
-bl_t f3(bl_t bl); // expected-error{{declaring function return value of type 'bl_t' (aka 'int (^const)(void)') is not allowed}}
+bl_t f3(bl_t bl); // expected-error{{declaring function return value of type 'bl_t' (aka 'int (__generic ^const)(void)') is not allowed}}
struct bl_s {
- int (^bl)(void); // expected-error {{the 'int (^const)(void)' type cannot be used to declare a structure or union field}}
+ int (^bl)(void); // expected-error {{the 'int (__generic ^const)(void)' type cannot be used to declare a structure or union field}}
};
void f4() {
@@ -45,16 +53,31 @@ void f5(int i) {
bl2_t bl2 = ^(int i) {
return 2;
};
- bl2_t arr[] = {bl1, bl2}; // expected-error {{array of 'bl2_t' (aka 'int (^const)(int)') type is invalid in OpenCL}}
+ bl2_t arr[] = {bl1, bl2}; // expected-error {{array of 'bl2_t' (aka 'int (__generic ^const)(int)') type is invalid in OpenCL}}
int tmp = i ? bl1(i) // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}}
: bl2(i); // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}}
}
// A block pointer type and all pointer operations are disallowed
-void f6(bl2_t *bl_ptr) { // expected-error{{pointer to type '__generic bl2_t' (aka 'int (^const __generic)(int)') is invalid in OpenCL}}
+void f6(bl2_t *bl_ptr) { // expected-error{{pointer to type '__generic bl2_t' (aka 'int (__generic ^const __generic)(int)') is invalid in OpenCL}}
bl2_t bl = ^(int i) {
return 1;
};
- bl2_t *p; // expected-error {{pointer to type '__generic bl2_t' (aka 'int (^const __generic)(int)') is invalid in OpenCL}}
- *bl; // expected-error {{invalid argument type 'bl2_t' (aka 'int (^const)(int)') to unary expression}}
- &bl; // expected-error {{invalid argument type 'bl2_t' (aka 'int (^const)(int)') to unary expression}}
+ bl2_t *p; // expected-error {{pointer to type '__generic bl2_t' (aka 'int (__generic ^const __generic)(int)') is invalid in OpenCL}}
+ *bl; // expected-error {{invalid argument type 'bl2_t' (aka 'int (__generic ^const)(int)') to unary expression}}
+ &bl; // expected-error {{invalid argument type 'bl2_t' (aka 'int (__generic ^const)(int)') to unary expression}}
+}
+// A block can't reference another block
+kernel void f7() {
+ bl2_t bl1 = ^(int i) {
+ return 1;
+ };
+ void (^bl2)(void) = ^{
+ int i = bl1(1); // expected-error {{cannot refer to a block inside block}}
+ };
+ void (^bl3)(void) = ^{
+ };
+ void (^bl4)(void) = ^{
+ bl3(); // expected-error {{cannot refer to a block inside block}}
+ };
+ return;
}
diff --git a/test/SemaOpenCL/invalid-logical-ops-1.1.cl b/test/SemaOpenCL/invalid-logical-ops-1.1.cl
deleted file mode 100644
index 2269dd322b36..000000000000
--- a/test/SemaOpenCL/invalid-logical-ops-1.1.cl
+++ /dev/null
@@ -1,57 +0,0 @@
-// RUN: %clang_cc1 %s -verify -cl-std=CL1.1 -triple x86_64-unknown-linux-gnu
-
-#pragma OPENCL EXTENSION cl_khr_fp64 : enable
-typedef __attribute__((ext_vector_type(4))) float float4;
-typedef __attribute__((ext_vector_type(4))) double double4;
-typedef __attribute__((ext_vector_type(4))) int int4;
-typedef __attribute__((ext_vector_type(4))) long long4;
-
-kernel void float_ops() {
- int flaf = 0.0f && 0.0f; // expected-error {{invalid operands}}
- int flof = 0.0f || 0.0f; // expected-error {{invalid operands}}
- float fbaf = 0.0f & 0.0f; // expected-error {{invalid operands}}
- float fbof = 0.0f | 0.0f; // expected-error {{invalid operands}}
- float fbxf = 0.0f ^ 0.0f; // expected-error {{invalid operands}}
- int flai = 0.0f && 0; // expected-error {{invalid operands}}
- int floi = 0.0f || 0; // expected-error {{invalid operands}}
- float ibaf = 0 & 0.0f; // expected-error {{invalid operands}}
- float ibof = 0 | 0.0f; // expected-error {{invalid operands}}
- float bnf = ~0.0f; // expected-error {{invalid argument type}}
- float lnf = !0.0f; // expected-error {{invalid argument type}}
-}
-
-kernel void vec_float_ops() {
- float4 f4 = (float4)(0, 0, 0, 0);
- int4 f4laf = f4 && 0.0f; // expected-error {{invalid operands}}
- int4 f4lof = f4 || 0.0f; // expected-error {{invalid operands}}
- float4 f4baf = f4 & 0.0f; // expected-error {{invalid operands}}
- float4 f4bof = f4 | 0.0f; // expected-error {{invalid operands}}
- float4 f4bxf = f4 ^ 0.0f; // expected-error {{invalid operands}}
- float bnf4 = ~f4; // expected-error {{invalid argument type}}
- int4 lnf4 = !f4; // expected-error {{invalid argument type}}
-}
-
-kernel void double_ops() {
- int flaf = 0.0 && 0.0; // expected-error {{invalid operands}}
- int flof = 0.0 || 0.0; // expected-error {{invalid operands}}
- double fbaf = 0.0 & 0.0; // expected-error {{invalid operands}}
- double fbof = 0.0 | 0.0; // expected-error {{invalid operands}}
- double fbxf = 0.0 ^ 0.0; // expected-error {{invalid operands}}
- int flai = 0.0 && 0; // expected-error {{invalid operands}}
- int floi = 0.0 || 0; // expected-error {{invalid operands}}
- double ibaf = 0 & 0.0; // expected-error {{invalid operands}}
- double ibof = 0 | 0.0; // expected-error {{invalid operands}}
- double bnf = ~0.0; // expected-error {{invalid argument type}}
- double lnf = !0.0; // expected-error {{invalid argument type}}
-}
-
-kernel void vec_double_ops() {
- double4 f4 = (double4)(0, 0, 0, 0);
- long4 f4laf = f4 && 0.0; // expected-error {{invalid operands}}
- long4 f4lof = f4 || 0.0; // expected-error {{invalid operands}}
- double4 f4baf = f4 & 0.0; // expected-error {{invalid operands}}
- double4 f4bof = f4 | 0.0; // expected-error {{invalid operands}}
- double4 f4bxf = f4 ^ 0.0; // expected-error {{invalid operands}}
- double bnf4 = ~f4; // expected-error {{invalid argument type}}
- long4 lnf4 = !f4; // expected-error {{invalid argument type}}
-}
diff --git a/test/SemaOpenCL/invalid-logical-ops-1.2.cl b/test/SemaOpenCL/logical-ops.cl
index bee52396cc6c..42501b14413e 100644
--- a/test/SemaOpenCL/invalid-logical-ops-1.2.cl
+++ b/test/SemaOpenCL/logical-ops.cl
@@ -1,4 +1,6 @@
+// RUN: %clang_cc1 %s -verify -cl-std=CL1.1 -triple x86_64-unknown-linux-gnu
// RUN: %clang_cc1 %s -verify -cl-std=CL1.2 -triple x86_64-unknown-linux-gnu
+// RUN: %clang_cc1 %s -verify -cl-std=CL2.0 -triple x86_64-unknown-linux-gnu
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
@@ -9,50 +11,107 @@ typedef __attribute__((ext_vector_type(4))) long long4;
kernel void float_ops() {
int flaf = 0.0f && 0.0f;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
int flof = 0.0f || 0.0f;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
float fbaf = 0.0f & 0.0f; // expected-error {{invalid operands}}
float fbof = 0.0f | 0.0f; // expected-error {{invalid operands}}
float fbxf = 0.0f ^ 0.0f; // expected-error {{invalid operands}}
int flai = 0.0f && 0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
int floi = 0.0f || 0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
float ibaf = 0 & 0.0f; // expected-error {{invalid operands}}
float ibof = 0 | 0.0f; // expected-error {{invalid operands}}
float bnf = ~0.0f;// expected-error {{invalid argument type}}
float lnf = !0.0f;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid argument type}}
+#endif
}
kernel void vec_float_ops() {
float4 f4 = (float4)(0, 0, 0, 0);
int4 f4laf = f4 && 0.0f;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
int4 f4lof = f4 || 0.0f;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
float4 f4baf = f4 & 0.0f; // expected-error {{invalid operands}}
float4 f4bof = f4 | 0.0f; // expected-error {{invalid operands}}
float4 f4bxf = f4 ^ 0.0f; // expected-error {{invalid operands}}
float bnf4 = ~f4; // expected-error {{invalid argument type}}
int4 lnf4 = !f4;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid argument type}}
+#endif
}
kernel void double_ops() {
int flaf = 0.0 && 0.0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
int flof = 0.0 || 0.0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
double fbaf = 0.0 & 0.0; // expected-error {{invalid operands}}
double fbof = 0.0 | 0.0; // expected-error {{invalid operands}}
double fbxf = 0.0 ^ 0.0; // expected-error {{invalid operands}}
int flai = 0.0 && 0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
int floi = 0.0 || 0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
double ibaf = 0 & 0.0; // expected-error {{invalid operands}}
double ibof = 0 | 0.0; // expected-error {{invalid operands}}
double bnf = ~0.0; // expected-error {{invalid argument type}}
double lnf = !0.0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid argument type}}
+#endif
}
kernel void vec_double_ops() {
double4 f4 = (double4)(0, 0, 0, 0);
long4 f4laf = f4 && 0.0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
long4 f4lof = f4 || 0.0;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid operands}}
+#endif
double4 f4baf = f4 & 0.0; // expected-error {{invalid operands}}
double4 f4bof = f4 | 0.0; // expected-error {{invalid operands}}
double4 f4bxf = f4 ^ 0.0; // expected-error {{invalid operands}}
double bnf4 = ~f4; // expected-error {{invalid argument type}}
long4 lnf4 = !f4;
+#if __OPENCL_C_VERSION__ < 120
+// expected-error@-2{{invalid argument type}}
+#endif
+}
+
+kernel void pointer_ops(){
+ global int* p;
+ bool b = !p;
+ b = p==0;
+ int i;
+ b = !&i;
+ b = &i==(int *)1;
}
diff --git a/test/SemaOpenCL/sampler_t.cl b/test/SemaOpenCL/sampler_t.cl
index c87b6da7c7e1..0dddeeb39013 100644
--- a/test/SemaOpenCL/sampler_t.cl
+++ b/test/SemaOpenCL/sampler_t.cl
@@ -30,7 +30,7 @@ constant sampler_t glb_smp8 = 1.0f; // expected-error{{initializing '__constant
constant sampler_t glb_smp9 = 0x100000000LL; // expected-error{{sampler_t initialization requires 32-bit integer, not 'long long'}}
-void foo(sampler_t);
+void foo(sampler_t); // expected-note{{passing argument to parameter here}}
constant struct sampler_s {
sampler_t smp; // expected-error{{the 'sampler_t' type cannot be used to declare a structure or union field}}
@@ -65,7 +65,8 @@ void kernel ker(sampler_t argsmp) {
foo(const_smp5);
foo(const_smp6);
foo(argsmp);
- foo(5); // expected-error{{sampler_t variable required - got 'int'}}
+ foo(5);
+ foo(5.0f); // expected-error {{passing 'float' to parameter of incompatible type 'sampler_t'}}
sampler_t sa[] = {argsmp, const_smp}; // expected-error {{array of 'sampler_t' type is invalid in OpenCL}}
foo(sa[0]);
foo(bad());
diff --git a/test/SemaOpenCL/types.cl b/test/SemaOpenCL/types.cl
new file mode 100644
index 000000000000..dc14800f3532
--- /dev/null
+++ b/test/SemaOpenCL/types.cl
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -fsyntax-only
+
+// expected-no-diagnostics
+
+// Check redefinition of standard types
+typedef atomic_int atomic_flag;
diff --git a/test/SemaOpenCL/vector_swizzle_length.cl b/test/SemaOpenCL/vector_swizzle_length.cl
new file mode 100644
index 000000000000..94e3f654d5d9
--- /dev/null
+++ b/test/SemaOpenCL/vector_swizzle_length.cl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+typedef float float8 __attribute__((ext_vector_type(8)));
+
+void foo() {
+ float8 f2 = (float8)(0, 0, 0, 0, 0, 0, 0, 0);
+
+ f2.s01234; // expected-error {{vector component access has invalid length 5. Supported: 1,2,3,4,8,16}}
+ f2.xyzxy; // expected-error {{vector component access has invalid length 5. Supported: 1,2,3,4,8,16}}
+}
diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp
index d70e86817849..3b7548d169b0 100644
--- a/test/SemaTemplate/alias-templates.cpp
+++ b/test/SemaTemplate/alias-templates.cpp
@@ -254,3 +254,14 @@ namespace PR31514 {
tuple_size<const int> t;
}
+
+namespace an_alias_template_is_not_a_class_template {
+ template<typename T> using Foo = int; // expected-note 2{{here}}
+ Foo x; // expected-error {{use of alias template 'Foo' requires template arguments}}
+ Foo<> y; // expected-error {{too few template arguments for alias template 'Foo'}}
+
+ template<template<typename> class Bar> void f() { // expected-note 2{{here}}
+ Bar x; // expected-error {{use of template template parameter 'Bar' requires template arguments}}
+ Bar<> y; // expected-error {{too few template arguments for template template parameter 'Bar'}}
+ }
+}
diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp
index 16e01a934630..74eb5a6ee581 100644
--- a/test/SemaTemplate/deduction.cpp
+++ b/test/SemaTemplate/deduction.cpp
@@ -481,3 +481,61 @@ namespace check_extended_pack {
int n;
void h() { g<0>(Y<0, &n>()); } // expected-error {{no matching function}}
}
+
+namespace dependent_template_template_param_non_type_param_type {
+ template<int N> struct A {
+ template<typename V = int, V M = 12, V (*Y)[M], template<V (*v)[M]> class W>
+ A(W<Y>);
+ };
+
+ int n[12];
+ template<int (*)[12]> struct Q {};
+ Q<&n> qn;
+ A<0> a(qn);
+}
+
+namespace dependent_list_deduction {
+ template<typename T, T V> void a(const int (&)[V]) {
+ static_assert(is_same<T, decltype(sizeof(0))>::value, "");
+ static_assert(V == 3, "");
+ }
+ template<typename T, T V> void b(const T (&)[V]) {
+ static_assert(is_same<T, int>::value, "");
+ static_assert(V == 3, "");
+ }
+ template<typename T, T V> void c(const T (&)[V]) {
+ static_assert(is_same<T, decltype(sizeof(0))>::value, "");
+ static_assert(V == 3, "");
+ }
+ void d() {
+ a({1, 2, 3});
+#if __cplusplus <= 201402L
+ // expected-error@-2 {{no match}} expected-note@-15 {{couldn't infer template argument 'T'}}
+#endif
+ b({1, 2, 3});
+ c({{}, {}, {}});
+#if __cplusplus <= 201402L
+ // expected-error@-2 {{no match}} expected-note@-12 {{couldn't infer template argument 'T'}}
+#endif
+ }
+
+ template<typename ...T> struct X;
+ template<int ...T> struct Y;
+ template<typename ...T, T ...V> void f(const T (&...p)[V]) {
+ static_assert(is_same<X<T...>, X<int, char, char>>::value, "");
+ static_assert(is_same<Y<V...>, Y<3, 2, 4>>::value, "");
+ }
+ template<typename ...T, T ...V> void g(const T (&...p)[V]) {
+ static_assert(is_same<X<T...>, X<int, decltype(sizeof(0))>>::value, "");
+ static_assert(is_same<Y<V...>, Y<2, 3>>::value, "");
+ }
+ void h() {
+ f({1, 2, 3}, {'a', 'b'}, "foo");
+ g({1, 2}, {{}, {}, {}});
+#if __cplusplus <= 201402
+ // expected-error@-2 {{no match}}
+ // expected-note@-9 {{deduced incomplete pack}}
+ // We deduce V$1 = (size_t)3, which in C++1z also deduces T$1 = size_t.
+#endif
+ }
+}
diff --git a/test/SemaTemplate/default-expr-arguments-3.cpp b/test/SemaTemplate/default-expr-arguments-3.cpp
index 9dc3b134300a..173609c04585 100644
--- a/test/SemaTemplate/default-expr-arguments-3.cpp
+++ b/test/SemaTemplate/default-expr-arguments-3.cpp
@@ -37,7 +37,7 @@ template <class T> struct class2 {
template struct class2<int>;
// CHECK: FunctionTemplateDecl {{.*}} f1
-// CHECK-NEXT: TemplateTypeParmDecl {{.*}} typename T
+// CHECK-NEXT: TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T
// CHECK-NEXT: FunctionDecl {{.*}} f1 'void (void)'
// CHECK: FunctionDecl {{.*}} f1 'void (void)'
// CHECK-NEXT: TemplateArgument type 'int'
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index 040a932e9720..010716dd1426 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -103,8 +103,8 @@ namespace PR7622 {
// Test that we do not crash.
class TC1 {
class TC2 {
- template // FIXME: error here.
- void foo() { }
+ template
+ void foo() { } // expected-error{{expected '<' after 'template'}}
};
};
diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp
index 7349fdf392d4..93a7231b8c7b 100644
--- a/test/SemaTemplate/injected-class-name.cpp
+++ b/test/SemaTemplate/injected-class-name.cpp
@@ -11,7 +11,10 @@ struct X<int***> {
typedef X<int***> *ptr;
};
-X<float>::X<int> xi = x; // expected-error{{qualified reference to 'X' is a constructor name rather than a template name wherever a constructor can be declared}}
+X<float>::X<int> xi = x; // expected-error{{qualified reference to 'X' is a constructor name rather than a template name}}
+void f() {
+ X<float>::X<int> xi = x; // expected-error{{qualified reference to 'X' is a constructor name rather than a template name}}
+}
// [temp.local]p1:
diff --git a/test/SemaTemplate/instantiate-c99.cpp b/test/SemaTemplate/instantiate-c99.cpp
index ae1552887b26..07d3fc7920ab 100644
--- a/test/SemaTemplate/instantiate-c99.cpp
+++ b/test/SemaTemplate/instantiate-c99.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// Test template instantiation for C99-specific features.
@@ -9,8 +11,13 @@ template<typename T, typename XType, typename YType>
struct DesigInit0 {
void f(XType x, YType y) {
T agg = {
+#if __cplusplus <= 199711L
.y = y, // expected-error{{does not refer}}
.x = x // expected-error{{does not refer}}
+#else
+ .y = static_cast<float>(y), // expected-error{{does not refer}}
+ .x = static_cast<float>(x) // expected-error{{does not refer}}
+#endif
};
}
};
@@ -44,7 +51,11 @@ template<typename T, int Subscript1, int Subscript2,
struct DesigArrayInit0 {
void f(Val1 val1, Val2 val2) {
T array = {
+#if __cplusplus <= 199711L
[Subscript1] = val1,
+#else
+ [Subscript1] = static_cast<int>(val1),
+#endif
[Subscript2] = val2 // expected-error{{exceeds array bounds}}
};
@@ -60,7 +71,11 @@ template<typename T, int Subscript1, int Subscript2,
struct DesigArrayRangeInit0 {
void f(Val1 val1) {
T array = {
+#if __cplusplus <= 199711L
[Subscript1...Subscript2] = val1 // expected-error{{exceeds}}
+#else
+ [Subscript1...Subscript2] = static_cast<int>(val1) // expected-error{{exceeds}}
+#endif
};
}
};
@@ -74,7 +89,11 @@ template struct DesigArrayRangeInit0<int[8], 5, 13, float>; // expected-note{{in
template<typename T, typename Arg1, typename Arg2>
struct CompoundLiteral0 {
T f(Arg1 a1, Arg2 a2) {
+#if __cplusplus <= 199711L
return (T){a1, a2};
+#else
+ return (T){static_cast<float>(a1), a2};
+#endif
}
};
diff --git a/test/SemaTemplate/instantiate-enum.cpp b/test/SemaTemplate/instantiate-enum.cpp
index 3da8eb4a6c0a..701d1919b27d 100644
--- a/test/SemaTemplate/instantiate-enum.cpp
+++ b/test/SemaTemplate/instantiate-enum.cpp
@@ -29,13 +29,14 @@ namespace PR6375 {
namespace EnumScoping {
template <typename T>
-class C {
+struct C {
+ struct X {};
enum {
value = 42
};
};
-void f(int i, C<int>::C c) {
+void f(int i, C<int>::X c) {
int value;
}
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index 159bccb2c992..5a9e2e30e851 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -39,8 +39,8 @@ public:
X<int>::C *c1;
X<float>::C *c2;
-X<int>::X *xi; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
-X<float>::X *xf; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
+X<int>::X *xi; // expected-error{{qualified reference to 'X' is a constructor name rather than a type}}
+X<float>::X *xf; // expected-error{{qualified reference to 'X' is a constructor name rather than a type}}
void test_naming() {
c1 = c2; // expected-error{{assigning to 'X<int>::C *' from incompatible type 'X<float>::C *'}}
diff --git a/test/SemaTemplate/member-access-ambig.cpp b/test/SemaTemplate/member-access-ambig.cpp
index 5c2d7617033f..a28698bb17e2 100644
--- a/test/SemaTemplate/member-access-ambig.cpp
+++ b/test/SemaTemplate/member-access-ambig.cpp
@@ -48,7 +48,7 @@ namespace AddrOfMember {
typedef int (A::*P);
template<typename T> struct S : T {
void f() {
- P(&T::X) // expected-error {{cannot cast from type 'int *' to member pointer type 'P'}}
+ P(&T::X) // expected-error {{cannot cast from type 'int *' to member pointer type 'AddrOfMember::P'}}
== &A::X;
}
};
diff --git a/test/SemaTemplate/ms-sizeof-missing-typename.cpp b/test/SemaTemplate/ms-sizeof-missing-typename.cpp
index ff8984feb795..9bafe6c98c2b 100644
--- a/test/SemaTemplate/ms-sizeof-missing-typename.cpp
+++ b/test/SemaTemplate/ms-sizeof-missing-typename.cpp
@@ -53,7 +53,7 @@ namespace ambiguous_missing_parens {
// expected-error@+1 {{'Q::U' instantiated to a class template, not a function template}}
template <typename T> void f() { int a = sizeof T::template U<0> + 4; }
struct Q {
- // expected-error@+1 {{class template declared here}}
+ // expected-note@+1 {{class template declared here}}
template <int> struct U {};
};
// expected-note-re@+1 {{in instantiation {{.*}} requested here}}
diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp
index 052c19ef639d..df5bf875f3be 100644
--- a/test/SemaTemplate/temp_arg.cpp
+++ b/test/SemaTemplate/temp_arg.cpp
@@ -10,7 +10,7 @@ A<int, 0, X> * a1;
A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}
-A a3; // expected-error{{use of class template 'A' requires template arguments}}
+A a4; // expected-error{{use of class template 'A' requires template arguments}}
namespace test0 {
template <class t> class foo {};
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 5b72b8c6549a..8658fb006060 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -455,3 +455,11 @@ namespace nondependent_default_arg_ordering {
X<int *, &m> y; f(y); // expected-error {{ambiguous}}
}
}
+
+namespace pointer_to_char_array {
+ typedef char T[4];
+ template<T *P> struct A { void f(); };
+ template<T *P> void A<P>::f() {}
+ T foo = "foo";
+ void g() { A<&foo>().f(); }
+}
diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp
index b0df9149c6e0..8f59dd724cc2 100644
--- a/test/SemaTemplate/temp_arg_template.cpp
+++ b/test/SemaTemplate/temp_arg_template.cpp
@@ -102,7 +102,42 @@ void foo() {
}
namespace CheckDependentNonTypeParamTypes {
- template<template<typename T, typename U, T v> class> struct A {}; // expected-note {{previous}}
- template<typename T, typename U, U v> struct B {}; // expected-note {{different type}}
- A<B> ab; // expected-error {{different template parameters}}
+ template<template<typename T, typename U, T v> class X> struct A {
+ void f() {
+ X<int, void*, 3> x; // expected-error {{does not refer to any declaration}}
+ }
+ void g() {
+ X<int, long, 3> x;
+ }
+ void h() {
+ // FIXME: If we accept A<B> at all, it's not obvious what should happen
+ // here. While parsing the template, we form
+ // X<unsigned char, int, (unsigned char)1234>
+ // but in the final instantiation do we get
+ // B<unsigned char, int, (int)1234>
+ // or
+ // B<unsigned char, int, (int)(unsigned char)1234>
+ // ?
+ X<unsigned char, int, 1234> x;
+ int check[x.value == 1234 ? 1 : -1];
+ }
+ };
+
+ template<typename T, typename U, U v> struct B { // expected-note {{parameter}}
+ static const U value = v;
+ };
+
+ // FIXME: This should probably be rejected, but the rules are at best unclear.
+ A<B> ab;
+
+ void use() {
+ ab.f(); // expected-note {{instantiation of}}
+ ab.g();
+ ab.h();
+ }
+}
+
+namespace PR32185 {
+ template<template<typename T, T> class U> struct A {};
+ template<template<typename T, T> class U> struct B : A<U> {};
}
diff --git a/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/test/SemaTemplate/temp_arg_template_cxx1z.cpp
index 703935dcd5c1..03ef78f8cf14 100644
--- a/test/SemaTemplate/temp_arg_template_cxx1z.cpp
+++ b/test/SemaTemplate/temp_arg_template_cxx1z.cpp
@@ -78,7 +78,7 @@ namespace Auto {
template<int*> struct IntPtr;
TInt<Auto> ia;
- TInt<AutoPtr> iap; // expected-error {{different template parameters}}
+ TInt<AutoPtr> iap; // FIXME: ill-formed (?)
TInt<DecltypeAuto> ida;
TInt<Int> ii;
TInt<IntPtr> iip; // expected-error {{different template parameters}}
@@ -90,27 +90,28 @@ namespace Auto {
TIntPtr<IntPtr> ipip;
TAuto<Auto> aa;
- TAuto<AutoPtr> aap; // expected-error {{different template parameters}}
- TAuto<Int> ai; // expected-error {{different template parameters}}
- TAuto<IntPtr> aip; // expected-error {{different template parameters}}
+ TAuto<AutoPtr> aap; // FIXME: ill-formed (?)
+ TAuto<Int> ai; // FIXME: ill-formed (?)
+ TAuto<IntPtr> aip; // FIXME: ill-formed (?)
TAutoPtr<Auto> apa;
TAutoPtr<AutoPtr> apap;
- TAutoPtr<Int> api; // expected-error {{different template parameters}}
- TAutoPtr<IntPtr> apip; // expected-error {{different template parameters}}
+ TAutoPtr<Int> api; // FIXME: ill-formed (?)
+ TAutoPtr<IntPtr> apip; // FIXME: ill-formed (?)
TDecltypeAuto<DecltypeAuto> dada;
- TDecltypeAuto<Int> dai; // expected-error {{different template parameters}}
- TDecltypeAuto<IntPtr> daip; // expected-error {{different template parameters}}
-
- // FIXME: It's completely unclear what should happen here. A case can be made
- // that 'auto' is more specialized, because it's always a prvalue, whereas
- // 'decltype(auto)' could have any value category. Under that interpretation,
- // we get the following results entirely backwards:
- TAuto<DecltypeAuto> ada; // expected-error {{different template parameters}}
- TAutoPtr<DecltypeAuto> apda; // expected-error {{different template parameters}}
+ TDecltypeAuto<Int> dai; // FIXME: ill-formed (?)
+ TDecltypeAuto<IntPtr> daip; // FIXME: ill-formed (?)
+
+ // FIXME: It's completely unclear what should happen here, but these results
+ // seem at least plausible:
+ TAuto<DecltypeAuto> ada;
+ TAutoPtr<DecltypeAuto> apda;
+ // Perhaps this case should be invalid, as there are valid 'decltype(auto)'
+ // parameters (such as 'user-defined-type &') that are not valid 'auto'
+ // parameters.
TDecltypeAuto<Auto> daa;
- TDecltypeAuto<AutoPtr> daa; // expected-error {{different template parameters}}
+ TDecltypeAuto<AutoPtr> daap; // FIXME: should probably be ill-formed
int n;
template<auto A, decltype(A) B = &n> struct SubstFailure;
diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp
index e8c9dfb5f5d2..0bb0cfad61fd 100644
--- a/test/SemaTemplate/temp_explicit.cpp
+++ b/test/SemaTemplate/temp_explicit.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wc++11-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wc++11-compat -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -std=c++11 %s
//
// Tests explicit instantiation of templates.
template<typename T, typename U = T> class X0 { };
@@ -98,7 +100,12 @@ void f4(X5<float&>::Inner2);
template struct X5<float&>::Inner2; // expected-note{{instantiation}}
namespace N3 {
- template struct N2::X5<int>::Inner2; // expected-warning {{explicit instantiation of 'Inner2' not in a namespace enclosing 'N2'}}
+ template struct N2::X5<int>::Inner2;
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{explicit instantiation of 'Inner2' not in a namespace enclosing 'N2'}}
+#else
+// expected-error@-4 {{explicit instantiation of 'Inner2' not in a namespace enclosing 'N2'}}
+#endif
}
struct X6 {
@@ -145,7 +152,17 @@ template struct ::N1::Inner::X8<float>;
namespace N2 {
using namespace N1;
- template struct X7<double>; // expected-warning{{must occur in namespace}}
-
- template struct X9<float>; // expected-warning{{must occur at global scope}}
+ template struct X7<double>;
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{explicit instantiation of 'N1::X7' must occur in namespace 'N1'}}
+#else
+// expected-error@-4 {{explicit instantiation of 'N1::X7' must occur in namespace 'N1'}}
+#endif
+
+ template struct X9<float>;
+#if __cplusplus <= 199711L
+// expected-warning@-2 {{explicit instantiation of 'X9' must occur at global scope}}
+#else
+// expected-error@-4 {{explicit instantiation of 'X9' must occur at global scope}}
+#endif
}
diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp
index e311b5832d0d..4e6e22479b3f 100644
--- a/test/SemaTemplate/template-id-expr.cpp
+++ b/test/SemaTemplate/template-id-expr.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++03 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// PR5336
template<typename FromCl>
struct isa_impl_cl {
@@ -98,7 +100,14 @@ void f5() {
template void f5<0>(); // expected-note {{in instantiation of function template specialization 'f5<0>' requested here}}
class C {};
-template <template <typename> class D> // expected-note{{previous use is here}}
+template <template <typename> class D>
class E {
- template class D<C>; // expected-error {{template template argument 'D' cannot be referenced with a class specifier}}
+ template class D<C>; // expected-error {{expected '<' after 'template'}}
+ template<> class D<C>; // expected-error {{cannot specialize a template template parameter}}
+ friend class D<C>; // expected-error {{type alias template 'D' cannot be referenced with a class specifier}}
};
+#if __cplusplus <= 199711L
+// expected-warning@+2 {{extension}}
+#endif
+template<typename T> using D = int; // expected-note {{declared here}}
+E<D> ed; // expected-note {{instantiation of}}
diff --git a/test/SemaTemplate/typename-specifier-3.cpp b/test/SemaTemplate/typename-specifier-3.cpp
index a463d88752c9..dfab5a0130f8 100644
--- a/test/SemaTemplate/typename-specifier-3.cpp
+++ b/test/SemaTemplate/typename-specifier-3.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// PR4364
-template<class T> struct a {
+template<class T> struct a { // expected-note {{here}}
T b() {
return typename T::x();
}
@@ -17,3 +17,4 @@ B c() {
// Some extra tests for invalid cases
template<class T> struct test2 { T b() { return typename T::a; } }; // expected-error{{expected '(' for function-style cast or type construction}}
template<class T> struct test3 { T b() { return typename a; } }; // expected-error{{expected a qualified name after 'typename'}}
+template<class T> struct test4 { T b() { return typename ::a; } }; // expected-error{{refers to non-type member}} expected-error{{expected '(' for function-style cast or type construction}}
diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp
index b36a103b65ae..99326f6a400a 100644
--- a/test/SemaTemplate/typename-specifier.cpp
+++ b/test/SemaTemplate/typename-specifier.cpp
@@ -102,7 +102,7 @@ D<long> struct_D; // expected-note {{in instantiation of template class 'D<long
template<typename T> struct E {
typedef typename T::foo foo;
- typedef typename foo::bar bar; // expected-error {{type 'foo' (aka 'double') cannot be used prior to '::' because it has no members}}
+ typedef typename foo::bar bar; // expected-error {{type 'E<F>::foo' (aka 'double') cannot be used prior to '::' because it has no members}}
};
struct F {
diff --git a/test/SemaTemplate/undefined-template.cpp b/test/SemaTemplate/undefined-template.cpp
index a03d0b7cff62..7dfe2fde94b0 100644
--- a/test/SemaTemplate/undefined-template.cpp
+++ b/test/SemaTemplate/undefined-template.cpp
@@ -134,6 +134,14 @@ void func_23(C1<int>::C2<long> *x) {
// expected-note@-1{{add an explicit instantiation declaration to suppress this warning if 'C1<int>::C2<long>::tmeth_2<int>' is explicitly instantiated in another translation unit}}
}
+namespace test_24 {
+ template <typename T> struct X {
+ friend void g(int);
+ operator int() { return 0; }
+ };
+ void h(X<int> x) { g(x); } // no warning for use of 'g' despite the declaration having been instantiated from a template
+}
+
int main() {
return 0;
}
diff --git a/test/SemaTemplate/value-dependent-null-pointer-constant.cpp b/test/SemaTemplate/value-dependent-null-pointer-constant.cpp
index 223500eac48c..29fd15e39576 100644
--- a/test/SemaTemplate/value-dependent-null-pointer-constant.cpp
+++ b/test/SemaTemplate/value-dependent-null-pointer-constant.cpp
@@ -1,17 +1,30 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T, int N>
struct X0 {
const char *f0(bool Cond) {
return Cond? "honk" : N;
+#if __cplusplus >= 201103L
+// expected-error@-2 {{incompatible operand types ('const char *' and 'int')}}
+#else
+// expected-no-diagnostics
+#endif
}
const char *f1(bool Cond) {
return Cond? N : "honk";
+#if __cplusplus >= 201103L
+// expected-error@-2 {{incompatible operand types ('int' and 'const char *')}}
+#endif
}
bool f2(const char *str) {
return str == N;
+#if __cplusplus >= 201103L
+// expected-error@-2 {{comparison between pointer and integer ('const char *' and 'int')}}
+#endif
}
};
diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp
index 4044f9e513db..3578350d8f84 100644
--- a/test/SemaTemplate/virtual-member-functions.cpp
+++ b/test/SemaTemplate/virtual-member-functions.cpp
@@ -1,5 +1,9 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -verify -std=c++11 %s
// RUN: %clang_cc1 -triple %ms_abi_triple -DMSABI -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple %ms_abi_triple -DMSABI -fsyntax-only -std=c++98 -verify %s
+// RUN: %clang_cc1 -triple %ms_abi_triple -DMSABI -fsyntax-only -std=c++11 -verify %s
namespace PR5557 {
template <class T> struct A {
@@ -76,34 +80,76 @@ namespace std {
}
namespace PR7114 {
- class A { virtual ~A(); }; // expected-note{{declared private here}}
+ class A { virtual ~A(); };
+#if __cplusplus <= 199711L
+ // expected-note@-2{{declared private here}}
+#else
+ // expected-note@-4 3 {{overridden virtual function is here}}
+#endif
template<typename T>
class B {
public:
- class Inner : public A { }; // expected-error{{base class 'PR7114::A' has private destructor}}
+ class Inner : public A { };
+#if __cplusplus <= 199711L
+// expected-error@-2{{base class 'PR7114::A' has private destructor}}
+#else
+// expected-error@-4 2 {{deleted function '~Inner' cannot override a non-deleted function}}
+// expected-note@-5 2 {{destructor of 'Inner' is implicitly deleted because base class 'PR7114::A' has an inaccessible destructor}}
+#ifdef MSABI
+// expected-note@-7 1 {{destructor of 'Inner' is implicitly deleted because base class 'PR7114::A' has an inaccessible destructor}}
+#endif
+#endif
+
static Inner i;
static const unsigned value = sizeof(i) == 4;
+#if __cplusplus >= 201103L
+// expected-note@-2 {{in instantiation of member class 'PR7114::B<int>::Inner' requested here}}
+// expected-note@-3 {{in instantiation of member class 'PR7114::B<float>::Inner' requested here}}
+#endif
};
int f() { return B<int>::value; }
+#if __cplusplus >= 201103L
+// expected-note@-2 {{in instantiation of template class 'PR7114::B<int>' requested here}}
+#endif
#ifdef MSABI
- void test_typeid(B<float>::Inner bfi) { // expected-note{{implicit destructor}}
+ void test_typeid(B<float>::Inner bfi) {
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor}}
+#else
+// expected-error@-4 {{attempt to use a deleted function}}
+// expected-note@-5 {{in instantiation of template class 'PR7114::B<float>' requested here}}
+#endif
+
(void)typeid(bfi);
#else
void test_typeid(B<float>::Inner bfi) {
- (void)typeid(bfi); // expected-note{{implicit destructor}}
+#if __cplusplus >= 201103L
+// expected-note@-2 {{in instantiation of template class 'PR7114::B<float>' requested here}}
+#endif
+ (void)typeid(bfi);
+#if __cplusplus <= 199711L
+// expected-note@-2 {{implicit destructor}}
+#endif
#endif
}
template<typename T>
struct X : A {
+#if __cplusplus >= 201103L
+// expected-error@-2 {{deleted function '~X' cannot override a non-deleted function}}
+// expected-note@-3 {{destructor of 'X<int>' is implicitly deleted because base class 'PR7114::A' has an inaccessible destructor}}
+#endif
void f() { }
};
void test_X(X<int> &xi, X<float> &xf) {
xi.f();
+#if __cplusplus >= 201103L
+// expected-note@-2 {{in instantiation of template class 'PR7114::X<int>' requested here}}
+#endif
}
}
diff --git a/test/Tooling/lit.local.cfg b/test/Tooling/lit.local.cfg
index da2a68b378cc..4cd8ba72fa76 100644
--- a/test/Tooling/lit.local.cfg
+++ b/test/Tooling/lit.local.cfg
@@ -1,2 +1,2 @@
-if config.root.clang_staticanalyzer == 0:
+if not config.root.clang_staticanalyzer:
config.unsupported = True
diff --git a/test/lit.cfg b/test/lit.cfg
index 7d8bebf57ff6..e4a13054ba81 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -202,7 +202,7 @@ if not lit_config.quiet:
# Plugins (loadable modules)
# TODO: This should be supplied by Makefile or autoconf.
if sys.platform in ['win32', 'cygwin']:
- has_plugins = (config.enable_shared == 1)
+ has_plugins = config.enable_shared
else:
has_plugins = True
@@ -253,12 +253,14 @@ def makeMSABITriple(triple):
if os == 'win32':
# If the OS is win32, we're done.
return triple
- if isa.startswith('x86') or isa == 'amd64' or re.match(r'i\d86', isa):
+ if isa.startswith('x86') or isa == 'amd64' or re.match(r'i\d86', isa):
# For x86 ISAs, adjust the OS.
return isa + '-' + vendor + '-win32'
# -win32 is not supported for non-x86 targets; use a default.
return 'i686-pc-win32'
+config.substitutions.append( ('%clang_analyze_cc1',
+ '%clang_cc1 -analyze %analyze') )
config.substitutions.append( ('%clang_cc1',
'%s -cc1 -internal-isystem %s -nostdsysteminc'
% (config.clang,
@@ -291,6 +293,9 @@ config.substitutions.append(
(' clang-cc ',
"""*** Do not use 'clang-cc' in tests, use '%clang_cc1'. ***""") )
config.substitutions.append(
+ (' clang -cc1 -analyze ',
+ """*** Do not use 'clang -cc1 -analyze' in tests, use '%clang_analyze_cc1'. ***""") )
+config.substitutions.append(
(' clang -cc1 ',
"""*** Do not use 'clang -cc1' in tests, use '%clang_cc1'. ***""") )
config.substitutions.append(
@@ -353,9 +358,12 @@ if config.clang_default_cxx_stdlib != '':
config.available_features.add('default-cxx-stdlib-set')
# Enabled/disabled features
-if config.clang_staticanalyzer != 0:
+if config.clang_staticanalyzer:
config.available_features.add("staticanalyzer")
+ if config.clang_staticanalyzer_z3 == '1':
+ config.available_features.add("z3")
+
# As of 2011.08, crash-recovery tests still do not pass on FreeBSD.
if platform.system() not in ['FreeBSD']:
config.available_features.add('crash-recovery')
@@ -432,7 +440,8 @@ if not re.match(r'.*-(cygwin)$', config.target_triple):
if platform.system() not in ['Windows']:
config.available_features.add('can-remove-opened-file')
-# Returns set of available features, registered-target(s) and asserts.
+# Returns set of available features, registered-target(s), asserts and
+# compile definitions.
def get_llvm_config_props():
set_of_features = set()
@@ -441,6 +450,7 @@ def get_llvm_config_props():
os.path.join(llvm_tools_dir, 'llvm-config'),
'--assertion-mode',
'--targets-built',
+ '--cxxflags'
],
stdout=subprocess.PIPE,
env=config.environment
@@ -455,6 +465,11 @@ def get_llvm_config_props():
for arch in cmd.stdout.readline().decode('ascii').split():
set_of_features.add(arch.lower() + '-registered-target')
+ # 3rd line contains compile definitions, search it to define if
+ # libstdc++ safe mode is set.
+ if re.search(r'-D_GLIBCXX_DEBUG\b', cmd.stdout.readline().decode('ascii')):
+ set_of_features.add('libstdcxx-safe-mode')
+
return set_of_features
config.available_features.update(get_llvm_config_props())
@@ -474,10 +489,10 @@ if 'Undefined' in config.llvm_use_sanitizer:
else:
config.available_features.add("not_ubsan")
-if config.enable_backtrace == "1":
+if config.enable_backtrace:
config.available_features.add("backtrace")
-if config.have_zlib == "1":
+if config.have_zlib:
config.available_features.add("zlib")
else:
config.available_features.add("nozlib")
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
index 5e1471f13115..8fdfbfc4842e 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.in
@@ -14,13 +14,14 @@ config.clang_tools_dir = "@CLANG_TOOLS_DIR@"
config.host_triple = "@LLVM_HOST_TRIPLE@"
config.target_triple = "@TARGET_TRIPLE@"
config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
-config.have_zlib = "@HAVE_LIBZ@"
-config.clang_arcmt = @ENABLE_CLANG_ARCMT@
+config.have_zlib = @HAVE_LIBZ@
+config.clang_arcmt = @CLANG_ENABLE_ARCMT@
config.clang_default_cxx_stdlib = "@CLANG_DEFAULT_CXX_STDLIB@"
-config.clang_staticanalyzer = @ENABLE_CLANG_STATIC_ANALYZER@
-config.clang_examples = @ENABLE_CLANG_EXAMPLES@
+config.clang_staticanalyzer = @CLANG_ENABLE_STATIC_ANALYZER@
+config.clang_staticanalyzer_z3 = "@CLANG_ANALYZER_WITH_Z3@"
+config.clang_examples = @CLANG_BUILD_EXAMPLES@
config.enable_shared = @ENABLE_SHARED@
-config.enable_backtrace = "@ENABLE_BACKTRACES@"
+config.enable_backtrace = @ENABLE_BACKTRACES@
config.host_arch = "@HOST_ARCH@"
# Support substitution of the tools and libs dirs with user parameters. This is
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index e0df5031d3e7..ad990e010eef 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -17,6 +17,7 @@ endif()
if (LLVM_BUILD_STATIC)
target_link_libraries(c-index-test
libclang_static
+ clangCodeGen
clangIndex
)
else()
@@ -24,8 +25,10 @@ else()
libclang
clangAST
clangBasic
+ clangCodeGen
clangFrontend
clangIndex
+ clangSerialization
)
endif()
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index dfb4b27bce61..0dde4c7cc764 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -710,6 +710,16 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
printf(":%d:%d", line, column);
}
+
+ if (clang_getCursorKind(Referenced) == CXCursor_TypedefDecl) {
+ CXType T = clang_getCursorType(Referenced);
+ if (clang_Type_isTransparentTagTypedef(T)) {
+ CXType Underlying = clang_getTypedefDeclUnderlyingType(Referenced);
+ CXString S = clang_getTypeSpelling(Underlying);
+ printf(" (Transparent: %s)", clang_getCString(S));
+ clang_disposeString(S);
+ }
+ }
}
if (clang_isCursorDefinition(Cursor))
@@ -4452,13 +4462,13 @@ int main(int argc, const char **argv) {
LIBXML_TEST_VERSION
#endif
+ if (argc > 1 && strcmp(argv[1], "core") == 0)
+ return indextest_core_main(argc, argv);
+
client_data.main_func = cindextest_main;
client_data.argc = argc;
client_data.argv = argv;
- if (argc > 1 && strcmp(argv[1], "core") == 0)
- client_data.main_func = indextest_core_main;
-
if (getenv("CINDEXTEST_NOTHREADS"))
return client_data.main_func(client_data.argc, client_data.argv);
diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp
index 0ab24fb6ccb9..4f2c3cb34a9b 100644
--- a/tools/c-index-test/core_main.cpp
+++ b/tools/c-index-test/core_main.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -15,6 +16,7 @@
#include "clang/Index/IndexDataConsumer.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Index/CodegenNameGenerator.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
@@ -49,6 +51,20 @@ static cl::extrahelp MoreHelp(
"invocation\n"
);
+static cl::opt<bool>
+DumpModuleImports("dump-imported-module-files",
+ cl::desc("Print symbols and input files from imported modules"));
+
+static cl::opt<bool>
+IncludeLocals("include-locals", cl::desc("Print local symbols"));
+
+static cl::opt<std::string>
+ModuleFilePath("module-file",
+ cl::desc("Path to module file to print symbols from"));
+static cl::opt<std::string>
+ ModuleFormat("fmodule-format", cl::init("raw"),
+ cl::desc("Container format for clang modules and PCH, 'raw' or 'obj'"));
+
}
} // anonymous namespace
@@ -134,7 +150,20 @@ public:
// Print Source Symbols
//===----------------------------------------------------------------------===//
-static bool printSourceSymbols(ArrayRef<const char *> Args) {
+static void dumpModuleFileInputs(serialization::ModuleFile &Mod,
+ ASTReader &Reader,
+ raw_ostream &OS) {
+ OS << "---- Module Inputs ----\n";
+ Reader.visitInputFiles(Mod, /*IncludeSystem=*/true, /*Complain=*/false,
+ [&](const serialization::InputFile &IF, bool isSystem) {
+ OS << (isSystem ? "system" : "user") << " | ";
+ OS << IF.getFile()->getName() << '\n';
+ });
+}
+
+static bool printSourceSymbols(ArrayRef<const char *> Args,
+ bool dumpModuleImports,
+ bool indexLocals) {
SmallVector<const char *, 4> ArgsWithProgName;
ArgsWithProgName.push_back("clang");
ArgsWithProgName.append(Args.begin(), Args.end());
@@ -144,8 +173,10 @@ static bool printSourceSymbols(ArrayRef<const char *> Args) {
if (!CInvok)
return true;
- auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(outs());
+ raw_ostream &OS = outs();
+ auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(OS);
IndexingOptions IndexOpts;
+ IndexOpts.IndexFunctionLocals = indexLocals;
std::unique_ptr<FrontendAction> IndexAction;
IndexAction = createIndexingAction(DataConsumer, IndexOpts,
/*WrappedAction=*/nullptr);
@@ -157,6 +188,50 @@ static bool printSourceSymbols(ArrayRef<const char *> Args) {
if (!Unit)
return true;
+ if (dumpModuleImports) {
+ if (auto Reader = Unit->getASTReader()) {
+ Reader->getModuleManager().visit([&](serialization::ModuleFile &Mod) -> bool {
+ OS << "==== Module " << Mod.ModuleName << " ====\n";
+ indexModuleFile(Mod, *Reader, DataConsumer, IndexOpts);
+ dumpModuleFileInputs(Mod, *Reader, OS);
+ return true; // skip module dependencies.
+ });
+ }
+ }
+
+ return false;
+}
+
+static bool printSourceSymbolsFromModule(StringRef modulePath,
+ StringRef format) {
+ FileSystemOptions FileSystemOpts;
+ auto pchContOps = std::make_shared<PCHContainerOperations>();
+ // Register the support for object-file-wrapped Clang modules.
+ pchContOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
+ auto pchRdr = pchContOps->getReaderOrNull(format);
+ if (!pchRdr) {
+ errs() << "unknown module format: " << format << '\n';
+ return true;
+ }
+
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ CompilerInstance::createDiagnostics(new DiagnosticOptions());
+ std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
+ modulePath, *pchRdr, Diags,
+ FileSystemOpts, /*UseDebugInfo=*/false,
+ /*OnlyLocalDecls=*/true, None,
+ /*CaptureDiagnostics=*/false,
+ /*AllowPCHWithCompilerErrors=*/true,
+ /*UserFilesAreVolatile=*/false);
+ if (!AU) {
+ errs() << "failed to create TU for: " << modulePath << '\n';
+ return true;
+ }
+
+ auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(outs());
+ IndexingOptions IndexOpts;
+ indexASTUnit(*AU, DataConsumer, IndexOpts);
+
return false;
}
@@ -219,11 +294,15 @@ int indextest_core_main(int argc, const char **argv) {
}
if (options::Action == ActionType::PrintSourceSymbols) {
+ if (!options::ModuleFilePath.empty()) {
+ return printSourceSymbolsFromModule(options::ModuleFilePath,
+ options::ModuleFormat);
+ }
if (CompArgs.empty()) {
errs() << "error: missing compiler args; pass '-- <compiler arguments>'\n";
return 1;
}
- return printSourceSymbols(CompArgs);
+ return printSourceSymbols(CompArgs, options::DumpModuleImports, options::IncludeLocals);
}
return 0;
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index b4177d4a86e2..dac11ff07771 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -140,6 +140,7 @@ public:
return clang::CreateASTDeclNodeLister();
if (ASTDump)
return clang::CreateASTDumper(ASTDumpFilter, /*DumpDecls=*/true,
+ /*Deserialize=*/false,
/*DumpLookups=*/false);
if (ASTPrint)
return clang::CreateASTPrinter(nullptr, ASTDumpFilter);
diff --git a/tools/clang-format-vs/.gitignore b/tools/clang-format-vs/.gitignore
index c9d25d96c8ec..270d840cb6d1 100644
--- a/tools/clang-format-vs/.gitignore
+++ b/tools/clang-format-vs/.gitignore
@@ -7,6 +7,5 @@
# Generated and copied files
/ClangFormat/Key.snk
-/ClangFormat/license.txt
/ClangFormat/clang-format.exe
/ClangFormat/source.extension.vsixmanifest
diff --git a/tools/clang-format-vs/CMakeLists.txt b/tools/clang-format-vs/CMakeLists.txt
index d07a4f6ed5da..1d44a47a3137 100644
--- a/tools/clang-format-vs/CMakeLists.txt
+++ b/tools/clang-format-vs/CMakeLists.txt
@@ -6,11 +6,6 @@ if (BUILD_CLANG_FORMAT_VS_PLUGIN)
"${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/clang-format.exe"
DEPENDS clang-format)
- add_custom_target(clang_format_license
- ${CMAKE_COMMAND} -E copy_if_different
- "${CLANG_SOURCE_DIR}/LICENSE.TXT"
- "${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/license.txt")
-
# Build number added to Clang version to ensure that new VSIX can be upgraded
string(TIMESTAMP CLANG_FORMAT_VSIX_BUILD %y%m%d%H%M UTC)
@@ -34,5 +29,5 @@ if (BUILD_CLANG_FORMAT_VS_PLUGIN)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/bin/Release/ClangFormat.vsix"
"${LLVM_TOOLS_BINARY_DIR}/ClangFormat.vsix"
- DEPENDS clang_format_exe_for_vsix clang_format_license)
+ DEPENDS clang_format_exe_for_vsix)
endif()
diff --git a/tools/clang-format-vs/ClangFormat.sln b/tools/clang-format-vs/ClangFormat.sln
index 73bf84e02858..46d742bce3f0 100644
--- a/tools/clang-format-vs/ClangFormat.sln
+++ b/tools/clang-format-vs/ClangFormat.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
+# Visual Studio 15
+VisualStudioVersion = 15.0.26228.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangFormat", "ClangFormat\ClangFormat.csproj", "{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}"
EndProject
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormat.csproj b/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
index 5ce601d649bf..e5b7ec008a1a 100644
--- a/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
+++ b/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
@@ -14,7 +14,7 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
+ <MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
@@ -59,8 +59,10 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="envdte, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
- <HintPath>..\packages\VSSDK.DTE.7.0.3\lib\net20\envdte.dll</HintPath>
- <EmbedInteropTypes>False</EmbedInteropTypes>
+ <EmbedInteropTypes>True</EmbedInteropTypes>
+ </Reference>
+ <Reference Include="envdte80, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualStudio.CoreUtility, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
@@ -116,10 +118,6 @@
<HintPath>..\packages\VSSDK.Text.10.0.4\lib\net40\Microsoft.VisualStudio.Text.UI.Wpf.dll</HintPath>
<Private>False</Private>
</Reference>
- <Reference Include="Microsoft.VisualStudio.TextManager.Interop">
- <HintPath>..\packages\VSSDK.TextManager.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.dll</HintPath>
- <Private>True</Private>
- </Reference>
<Reference Include="Microsoft.VisualStudio.TextManager.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>False</Private>
</Reference>
@@ -146,42 +144,6 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
- <COMReference Include="EnvDTE">
- <Guid>{80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2}</Guid>
- <VersionMajor>8</VersionMajor>
- <VersionMinor>0</VersionMinor>
- <Lcid>0</Lcid>
- <WrapperTool>primary</WrapperTool>
- <Isolated>False</Isolated>
- <EmbedInteropTypes>False</EmbedInteropTypes>
- </COMReference>
- <COMReference Include="EnvDTE100">
- <Guid>{26AD1324-4B7C-44BC-84F8-B86AED45729F}</Guid>
- <VersionMajor>10</VersionMajor>
- <VersionMinor>0</VersionMinor>
- <Lcid>0</Lcid>
- <WrapperTool>primary</WrapperTool>
- <Isolated>False</Isolated>
- <EmbedInteropTypes>False</EmbedInteropTypes>
- </COMReference>
- <COMReference Include="EnvDTE80">
- <Guid>{1A31287A-4D7D-413E-8E32-3B374931BD89}</Guid>
- <VersionMajor>8</VersionMajor>
- <VersionMinor>0</VersionMinor>
- <Lcid>0</Lcid>
- <WrapperTool>primary</WrapperTool>
- <Isolated>False</Isolated>
- <EmbedInteropTypes>False</EmbedInteropTypes>
- </COMReference>
- <COMReference Include="EnvDTE90">
- <Guid>{2CE2370E-D744-4936-A090-3FFFE667B0E1}</Guid>
- <VersionMajor>9</VersionMajor>
- <VersionMinor>0</VersionMinor>
- <Lcid>0</Lcid>
- <WrapperTool>primary</WrapperTool>
- <Isolated>False</Isolated>
- <EmbedInteropTypes>False</EmbedInteropTypes>
- </COMReference>
<COMReference Include="Microsoft.VisualStudio.CommandBars">
<Guid>{1CBA492E-7263-47BB-87FE-639000619B15}</Guid>
<VersionMajor>8</VersionMajor>
@@ -214,6 +176,8 @@
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PkgCmdID.cs" />
+ <Compile Include="RunningDocTableEventsDispatcher.cs" />
+ <Compile Include="Vsix.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
@@ -228,7 +192,9 @@
</ItemGroup>
<ItemGroup>
<None Include="Key.snk" />
- <None Include="packages.config" />
+ <None Include="packages.config">
+ <SubType>Designer</SubType>
+ </None>
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
@@ -292,4 +258,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
index c7eac42211ad..d16d6d504147 100644
--- a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
+++ b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
@@ -12,12 +12,11 @@
//
//===----------------------------------------------------------------------===//
-using Microsoft.VisualStudio.Editor;
+using EnvDTE;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
-using Microsoft.VisualStudio.TextManager.Interop;
using System;
using System.Collections;
using System.ComponentModel;
@@ -25,6 +24,7 @@ using System.ComponentModel.Design;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml.Linq;
+using System.Linq;
namespace LLVM.ClangFormat
{
@@ -36,6 +36,17 @@ namespace LLVM.ClangFormat
private string fallbackStyle = "LLVM";
private bool sortIncludes = false;
private string style = "file";
+ private bool formatOnSave = false;
+ private string formatOnSaveFileExtensions =
+ ".c;.cpp;.cxx;.cc;.tli;.tlh;.h;.hh;.hpp;.hxx;.hh;.inl" +
+ ".java;.js;.ts;.m;.mm;.proto;.protodevel;.td";
+
+ public OptionPageGrid Clone()
+ {
+ // Use MemberwiseClone to copy value types.
+ var clone = (OptionPageGrid)MemberwiseClone();
+ return clone;
+ }
public class StyleConverter : TypeConverter
{
@@ -74,7 +85,7 @@ namespace LLVM.ClangFormat
}
}
- [Category("LLVM/Clang")]
+ [Category("Format Options")]
[DisplayName("Style")]
[Description("Coding style, currently supports:\n" +
" - Predefined styles ('LLVM', 'Google', 'Chromium', 'Mozilla', 'WebKit').\n" +
@@ -121,7 +132,7 @@ namespace LLVM.ClangFormat
}
}
- [Category("LLVM/Clang")]
+ [Category("Format Options")]
[DisplayName("Assume Filename")]
[Description("When reading from stdin, clang-format assumes this " +
"filename to look for a style config file (with 'file' style) " +
@@ -142,7 +153,7 @@ namespace LLVM.ClangFormat
}
}
- [Category("LLVM/Clang")]
+ [Category("Format Options")]
[DisplayName("Fallback Style")]
[Description("The name of the predefined style used as a fallback in case clang-format " +
"is invoked with 'file' style, but can not find the configuration file.\n" +
@@ -154,7 +165,7 @@ namespace LLVM.ClangFormat
set { fallbackStyle = value; }
}
- [Category("LLVM/Clang")]
+ [Category("Format Options")]
[DisplayName("Sort includes")]
[Description("Sort touched include lines.\n\n" +
"See also: http://clang.llvm.org/docs/ClangFormat.html.")]
@@ -163,20 +174,48 @@ namespace LLVM.ClangFormat
get { return sortIncludes; }
set { sortIncludes = value; }
}
+
+ [Category("Format On Save")]
+ [DisplayName("Enable")]
+ [Description("Enable running clang-format when modified files are saved. " +
+ "Will only format if Style is found (ignores Fallback Style)."
+ )]
+ public bool FormatOnSave
+ {
+ get { return formatOnSave; }
+ set { formatOnSave = value; }
+ }
+
+ [Category("Format On Save")]
+ [DisplayName("File extensions")]
+ [Description("When formatting on save, clang-format will be applied only to " +
+ "files with these extensions.")]
+ public string FormatOnSaveFileExtensions
+ {
+ get { return formatOnSaveFileExtensions; }
+ set { formatOnSaveFileExtensions = value; }
+ }
}
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[ProvideMenuResource("Menus.ctmenu", 1)]
+ [ProvideAutoLoad(UIContextGuids80.SolutionExists)] // Load package on solution load
[Guid(GuidList.guidClangFormatPkgString)]
[ProvideOptionPage(typeof(OptionPageGrid), "LLVM/Clang", "ClangFormat", 0, 0, true)]
public sealed class ClangFormatPackage : Package
{
#region Package Members
+
+ RunningDocTableEventsDispatcher _runningDocTableEventsDispatcher;
+
protected override void Initialize()
{
base.Initialize();
+ _runningDocTableEventsDispatcher = new RunningDocTableEventsDispatcher(this);
+ _runningDocTableEventsDispatcher.BeforeSave += OnBeforeSave;
+
var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService != null)
{
@@ -195,6 +234,11 @@ namespace LLVM.ClangFormat
}
#endregion
+ OptionPageGrid GetUserOptions()
+ {
+ return (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
+ }
+
private void MenuItemCallback(object sender, EventArgs args)
{
var mc = sender as System.ComponentModel.Design.MenuCommand;
@@ -204,21 +248,45 @@ namespace LLVM.ClangFormat
switch (mc.CommandID.ID)
{
case (int)PkgCmdIDList.cmdidClangFormatSelection:
- FormatSelection();
+ FormatSelection(GetUserOptions());
break;
case (int)PkgCmdIDList.cmdidClangFormatDocument:
- FormatDocument();
+ FormatDocument(GetUserOptions());
break;
}
}
+ private static bool FileHasExtension(string filePath, string fileExtensions)
+ {
+ var extensions = fileExtensions.ToLower().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+ return extensions.Contains(Path.GetExtension(filePath).ToLower());
+ }
+
+ private void OnBeforeSave(object sender, Document document)
+ {
+ var options = GetUserOptions();
+
+ if (!options.FormatOnSave)
+ return;
+
+ if (!FileHasExtension(document.FullName, options.FormatOnSaveFileExtensions))
+ return;
+
+ if (!Vsix.IsDocumentDirty(document))
+ return;
+
+ var optionsWithNoFallbackStyle = GetUserOptions().Clone();
+ optionsWithNoFallbackStyle.FallbackStyle = "none";
+ FormatDocument(document, optionsWithNoFallbackStyle);
+ }
+
/// <summary>
/// Runs clang-format on the current selection
/// </summary>
- private void FormatSelection()
+ private void FormatSelection(OptionPageGrid options)
{
- IWpfTextView view = GetCurrentView();
+ IWpfTextView view = Vsix.GetCurrentView();
if (view == null)
// We're not in a text view.
return;
@@ -231,34 +299,43 @@ namespace LLVM.ClangFormat
// of the file.
if (start >= text.Length && text.Length > 0)
start = text.Length - 1;
- string path = GetDocumentParent(view);
- string filePath = GetDocumentPath(view);
+ string path = Vsix.GetDocumentParent(view);
+ string filePath = Vsix.GetDocumentPath(view);
- RunClangFormatAndApplyReplacements(text, start, length, path, filePath, view);
+ RunClangFormatAndApplyReplacements(text, start, length, path, filePath, options, view);
}
/// <summary>
/// Runs clang-format on the current document
/// </summary>
- private void FormatDocument()
+ private void FormatDocument(OptionPageGrid options)
+ {
+ FormatView(Vsix.GetCurrentView(), options);
+ }
+
+ private void FormatDocument(Document document, OptionPageGrid options)
+ {
+ FormatView(Vsix.GetDocumentView(document), options);
+ }
+
+ private void FormatView(IWpfTextView view, OptionPageGrid options)
{
- IWpfTextView view = GetCurrentView();
if (view == null)
// We're not in a text view.
return;
- string filePath = GetDocumentPath(view);
+ string filePath = Vsix.GetDocumentPath(view);
var path = Path.GetDirectoryName(filePath);
string text = view.TextBuffer.CurrentSnapshot.GetText();
- RunClangFormatAndApplyReplacements(text, 0, text.Length, path, filePath, view);
+ RunClangFormatAndApplyReplacements(text, 0, text.Length, path, filePath, options, view);
}
- private void RunClangFormatAndApplyReplacements(string text, int offset, int length, string path, string filePath, IWpfTextView view)
+ private void RunClangFormatAndApplyReplacements(string text, int offset, int length, string path, string filePath, OptionPageGrid options, IWpfTextView view)
{
try
{
- string replacements = RunClangFormat(text, offset, length, path, filePath);
+ string replacements = RunClangFormat(text, offset, length, path, filePath, options);
ApplyClangFormatReplacements(replacements, view);
}
catch (Exception e)
@@ -283,7 +360,7 @@ namespace LLVM.ClangFormat
///
/// Formats the text range starting at offset of the given length.
/// </summary>
- private string RunClangFormat(string text, int offset, int length, string path, string filePath)
+ private static string RunClangFormat(string text, int offset, int length, string path, string filePath, OptionPageGrid options)
{
string vsixPath = Path.GetDirectoryName(
typeof(ClangFormatPackage).Assembly.Location);
@@ -293,16 +370,16 @@ namespace LLVM.ClangFormat
process.StartInfo.FileName = vsixPath + "\\clang-format.exe";
// Poor man's escaping - this will not work when quotes are already escaped
// in the input (but we don't need more).
- string style = GetStyle().Replace("\"", "\\\"");
- string fallbackStyle = GetFallbackStyle().Replace("\"", "\\\"");
+ string style = options.Style.Replace("\"", "\\\"");
+ string fallbackStyle = options.FallbackStyle.Replace("\"", "\\\"");
process.StartInfo.Arguments = " -offset " + offset +
" -length " + length +
" -output-replacements-xml " +
" -style \"" + style + "\"" +
" -fallback-style \"" + fallbackStyle + "\"";
- if (GetSortIncludes())
+ if (options.SortIncludes)
process.StartInfo.Arguments += " -sort-includes ";
- string assumeFilename = GetAssumeFilename();
+ string assumeFilename = options.AssumeFilename;
if (string.IsNullOrEmpty(assumeFilename))
assumeFilename = filePath;
if (!string.IsNullOrEmpty(assumeFilename))
@@ -352,7 +429,7 @@ namespace LLVM.ClangFormat
/// <summary>
/// Applies the clang-format replacements (xml) to the current view
/// </summary>
- private void ApplyClangFormatReplacements(string replacements, IWpfTextView view)
+ private static void ApplyClangFormatReplacements(string replacements, IWpfTextView view)
{
// clang-format returns no replacements if input text is empty
if (replacements.Length == 0)
@@ -369,70 +446,5 @@ namespace LLVM.ClangFormat
}
edit.Apply();
}
-
- /// <summary>
- /// Returns the currently active view if it is a IWpfTextView.
- /// </summary>
- private IWpfTextView GetCurrentView()
- {
- // The SVsTextManager is a service through which we can get the active view.
- var textManager = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));
- IVsTextView textView;
- textManager.GetActiveView(1, null, out textView);
-
- // Now we have the active view as IVsTextView, but the text interfaces we need
- // are in the IWpfTextView.
- var userData = (IVsUserData)textView;
- if (userData == null)
- return null;
- Guid guidWpfViewHost = DefGuidList.guidIWpfTextViewHost;
- object host;
- userData.GetData(ref guidWpfViewHost, out host);
- return ((IWpfTextViewHost)host).TextView;
- }
-
- private string GetStyle()
- {
- var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
- return page.Style;
- }
-
- private string GetAssumeFilename()
- {
- var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
- return page.AssumeFilename;
- }
-
- private string GetFallbackStyle()
- {
- var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
- return page.FallbackStyle;
- }
-
- private bool GetSortIncludes()
- {
- var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
- return page.SortIncludes;
- }
-
- private string GetDocumentParent(IWpfTextView view)
- {
- ITextDocument document;
- if (view.TextBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
- {
- return Directory.GetParent(document.FilePath).ToString();
- }
- return null;
- }
-
- private string GetDocumentPath(IWpfTextView view)
- {
- ITextDocument document;
- if (view.TextBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
- {
- return document.FilePath;
- }
- return null;
- }
}
}
diff --git a/tools/clang-format-vs/ClangFormat/RunningDocTableEventsDispatcher.cs b/tools/clang-format-vs/ClangFormat/RunningDocTableEventsDispatcher.cs
new file mode 100644
index 000000000000..163f68dbda3c
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/RunningDocTableEventsDispatcher.cs
@@ -0,0 +1,79 @@
+using EnvDTE;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using System.Linq;
+
+namespace LLVM.ClangFormat
+{
+ // Exposes event sources for IVsRunningDocTableEvents3 events.
+ internal sealed class RunningDocTableEventsDispatcher : IVsRunningDocTableEvents3
+ {
+ private RunningDocumentTable _runningDocumentTable;
+ private DTE _dte;
+
+ public delegate void OnBeforeSaveHander(object sender, Document document);
+ public event OnBeforeSaveHander BeforeSave;
+
+ public RunningDocTableEventsDispatcher(Package package)
+ {
+ _runningDocumentTable = new RunningDocumentTable(package);
+ _runningDocumentTable.Advise(this);
+ _dte = (DTE)Package.GetGlobalService(typeof(DTE));
+ }
+
+ public int OnAfterAttributeChange(uint docCookie, uint grfAttribs)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, IVsHierarchy pHierOld, uint itemidOld, string pszMkDocumentOld, IVsHierarchy pHierNew, uint itemidNew, string pszMkDocumentNew)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnAfterSave(uint docCookie)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnBeforeSave(uint docCookie)
+ {
+ if (BeforeSave != null)
+ {
+ var document = FindDocumentByCookie(docCookie);
+ if (document != null) // Not sure why this happens sometimes
+ {
+ BeforeSave(this, FindDocumentByCookie(docCookie));
+ }
+ }
+ return VSConstants.S_OK;
+ }
+
+ private Document FindDocumentByCookie(uint docCookie)
+ {
+ var documentInfo = _runningDocumentTable.GetDocumentInfo(docCookie);
+ return _dte.Documents.Cast<Document>().FirstOrDefault(doc => doc.FullName == documentInfo.Moniker);
+ }
+ }
+}
diff --git a/tools/clang-format-vs/ClangFormat/Vsix.cs b/tools/clang-format-vs/ClangFormat/Vsix.cs
new file mode 100644
index 000000000000..0d86cb59828a
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/Vsix.cs
@@ -0,0 +1,96 @@
+using EnvDTE;
+using Microsoft.VisualStudio.Editor;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.TextManager.Interop;
+using System;
+using System.IO;
+
+namespace LLVM.ClangFormat
+{
+ internal sealed class Vsix
+ {
+ /// <summary>
+ /// Returns the currently active view if it is a IWpfTextView.
+ /// </summary>
+ public static IWpfTextView GetCurrentView()
+ {
+ // The SVsTextManager is a service through which we can get the active view.
+ var textManager = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));
+ IVsTextView textView;
+ textManager.GetActiveView(1, null, out textView);
+
+ // Now we have the active view as IVsTextView, but the text interfaces we need
+ // are in the IWpfTextView.
+ return VsToWpfTextView(textView);
+ }
+
+ public static bool IsDocumentDirty(Document document)
+ {
+ var textView = GetDocumentView(document);
+ var textDocument = GetTextDocument(textView);
+ return textDocument?.IsDirty == true;
+ }
+
+ public static IWpfTextView GetDocumentView(Document document)
+ {
+ var textView = GetVsTextViewFrompPath(document.FullName);
+ return VsToWpfTextView(textView);
+ }
+
+ public static IWpfTextView VsToWpfTextView(IVsTextView textView)
+ {
+ var userData = (IVsUserData)textView;
+ if (userData == null)
+ return null;
+ Guid guidWpfViewHost = DefGuidList.guidIWpfTextViewHost;
+ object host;
+ userData.GetData(ref guidWpfViewHost, out host);
+ return ((IWpfTextViewHost)host).TextView;
+ }
+
+ public static IVsTextView GetVsTextViewFrompPath(string filePath)
+ {
+ // From http://stackoverflow.com/a/2427368/4039972
+ var dte2 = (EnvDTE80.DTE2)Package.GetGlobalService(typeof(SDTE));
+ var sp = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)dte2;
+ var serviceProvider = new Microsoft.VisualStudio.Shell.ServiceProvider(sp);
+
+ IVsUIHierarchy uiHierarchy;
+ uint itemID;
+ IVsWindowFrame windowFrame;
+ if (VsShellUtilities.IsDocumentOpen(serviceProvider, filePath, Guid.Empty,
+ out uiHierarchy, out itemID, out windowFrame))
+ {
+ // Get the IVsTextView from the windowFrame.
+ return VsShellUtilities.GetTextView(windowFrame);
+ }
+ return null;
+ }
+
+ public static ITextDocument GetTextDocument(IWpfTextView view)
+ {
+ ITextDocument document;
+ if (view != null && view.TextBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
+ return document;
+ return null;
+ }
+
+ public static string GetDocumentParent(IWpfTextView view)
+ {
+ ITextDocument document = GetTextDocument(view);
+ if (document != null)
+ {
+ return Directory.GetParent(document.FilePath).ToString();
+ }
+ return null;
+ }
+
+ public static string GetDocumentPath(IWpfTextView view)
+ {
+ return GetTextDocument(view)?.FilePath;
+ }
+ }
+}
diff --git a/tools/clang-format-vs/ClangFormat/license.txt b/tools/clang-format-vs/ClangFormat/license.txt
new file mode 100644
index 000000000000..9966c8123f5b
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/license.txt
@@ -0,0 +1,39 @@
+====================
+LLVM Release License
+====================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2007-2017 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with 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:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission.
+
+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 CONTRIBUTORS 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 WITH THE SOFTWARE.
+
+====================
+The LLVM software contains code written by third parties. Such software will have its own individual LICENSE.TXT file in the directory in which it appears. This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License applies to all code in the LLVM Distribution, and nothing in any of the other licenses gives permission to use the names of the LLVM Team or the University of Illinois to endorse or promote products derived from this Software.
+
+The following pieces of software have additional or alternate copyrights, licenses, and/or restrictions:
+
+Program Directory
+------- ---------
+<none yet>
+
diff --git a/tools/clang-format-vs/ClangFormat/packages.config b/tools/clang-format-vs/ClangFormat/packages.config
index 38f64ed3a615..07dc281178f5 100644
--- a/tools/clang-format-vs/ClangFormat/packages.config
+++ b/tools/clang-format-vs/ClangFormat/packages.config
@@ -2,7 +2,6 @@
<packages>
<package id="VSSDK.CoreUtility" version="10.0.4" targetFramework="net40" />
<package id="VSSDK.CoreUtility.10" version="10.0.4" targetFramework="net40" />
- <package id="VSSDK.DTE" version="7.0.3" targetFramework="net40" />
<package id="VSSDK.Editor" version="10.0.4" targetFramework="net40" />
<package id="VSSDK.Editor.10" version="10.0.4" targetFramework="net40" />
<package id="VSSDK.IDE" version="7.0.4" targetFramework="net40" />
diff --git a/tools/clang-format-vs/source.extension.vsixmanifest.in b/tools/clang-format-vs/source.extension.vsixmanifest.in
index 496fa40063b7..c0545e68716a 100644
--- a/tools/clang-format-vs/source.extension.vsixmanifest.in
+++ b/tools/clang-format-vs/source.extension.vsixmanifest.in
@@ -1,36 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-<Vsix Version="1.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
- <Identifier Id="20dbc914-1c7a-4992-b236-ef58b37850eb">
- <Name>ClangFormat</Name>
- <Author>LLVM</Author>
- <Version>@CLANG_FORMAT_VS_VERSION@</Version>
+<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
+ <Metadata>
+ <Identity Id="20dbc914-1c7a-4992-b236-ef58b37850eb" Version="@CLANG_FORMAT_VS_VERSION@" Language="en-US" Publisher="LLVM"/>
+ <DisplayName>ClangFormat</DisplayName>
<Description xml:space="preserve">A tool to format C/C++/Obj-C code.</Description>
- <Locale>1033</Locale>
- <MoreInfoUrl>http://clang.llvm.org/docs/ClangFormat.html</MoreInfoUrl>
+ <MoreInfo>http://clang.llvm.org/docs/ClangFormat.html</MoreInfo>
<License>license.txt</License>
- <InstalledByMsi>false</InstalledByMsi>
- <SupportedProducts>
- <VisualStudio Version="10.0">
- <Edition>Pro</Edition>
- </VisualStudio>
- <VisualStudio Version="11.0">
- <Edition>Pro</Edition>
- </VisualStudio>
- <VisualStudio Version="12.0">
- <Edition>Pro</Edition>
- </VisualStudio>
- <VisualStudio Version="14.0">
- <Edition>Pro</Edition>
- </VisualStudio>
- </SupportedProducts>
- <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.0" />
- </Identifier>
- <References>
- <Reference Id="Microsoft.VisualStudio.MPF" MinVersion="10.0">
- <Name>Visual Studio MPF</Name>
- </Reference>
- </References>
- <Content>
- <VsPackage>|%CurrentProject%;PkgdefProjectOutputGroup|</VsPackage>
- </Content>
-</Vsix>
+ </Metadata>
+ <Installation InstalledByMsi="false">
+ <InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[11.0, 15.0]" />
+ </Installation>
+ <Dependencies>
+ <Dependency Id="Microsoft.VisualStudio.MPF" MinVersion="11.0" DisplayName="Visual Studio MPF" />
+ </Dependencies>
+ <Prerequisites>
+ <Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[11.0,)" DisplayName="Visual Studio core editor" />
+ </Prerequisites>
+</PackageManifest>
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index 6c50daf53834..ac0d0a8512f4 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -236,8 +236,15 @@ static void outputReplacementsXML(const Replacements &Replaces) {
// Returns true on error.
static bool format(StringRef FileName) {
+ if (!OutputXML && Inplace && FileName == "-") {
+ errs() << "error: cannot use -i when reading from stdin.\n";
+ return false;
+ }
+ // On Windows, overwriting a file with an open file mapping doesn't work,
+ // so read the whole file into memory when formatting in-place.
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
- MemoryBuffer::getFileOrSTDIN(FileName);
+ !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName) :
+ MemoryBuffer::getFileOrSTDIN(FileName);
if (std::error_code EC = CodeOrErr.getError()) {
errs() << EC.message() << "\n";
return true;
@@ -249,12 +256,18 @@ static bool format(StringRef FileName) {
if (fillRanges(Code.get(), Ranges))
return true;
StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName;
- FormatStyle FormatStyle =
+
+ llvm::Expected<FormatStyle> FormatStyle =
getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer());
+ if (!FormatStyle) {
+ llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
+ return true;
+ }
+
if (SortIncludes.getNumOccurrences() != 0)
- FormatStyle.SortIncludes = SortIncludes;
+ FormatStyle->SortIncludes = SortIncludes;
unsigned CursorPosition = Cursor;
- Replacements Replaces = sortIncludes(FormatStyle, Code->getBuffer(), Ranges,
+ Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges,
AssumedFileName, &CursorPosition);
auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces);
if (!ChangedCode) {
@@ -264,7 +277,7 @@ static bool format(StringRef FileName) {
// Get new affected ranges after sorting `#includes`.
Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
bool IncompleteFormat = false;
- Replacements FormatChanges = reformat(FormatStyle, *ChangedCode, Ranges,
+ Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges,
AssumedFileName, &IncompleteFormat);
Replaces = Replaces.merge(FormatChanges);
if (OutputXML) {
@@ -291,9 +304,7 @@ static bool format(StringRef FileName) {
Rewriter Rewrite(Sources, LangOptions());
tooling::applyAllReplacements(Replaces, Rewrite);
if (Inplace) {
- if (FileName == "-")
- errs() << "error: cannot use -i when reading from stdin.\n";
- else if (Rewrite.overwriteChangedFiles())
+ if (Rewrite.overwriteChangedFiles())
return true;
} else {
if (Cursor.getNumOccurrences() != 0)
@@ -334,10 +345,15 @@ int main(int argc, const char **argv) {
cl::PrintHelpMessage();
if (DumpConfig) {
- std::string Config =
- clang::format::configurationAsText(clang::format::getStyle(
+ llvm::Expected<clang::format::FormatStyle> FormatStyle =
+ clang::format::getStyle(
Style, FileNames.empty() ? AssumeFileName : FileNames[0],
- FallbackStyle));
+ FallbackStyle);
+ if (!FormatStyle) {
+ llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
+ return 1;
+ }
+ std::string Config = clang::format::configurationAsText(*FormatStyle);
outs() << Config << "\n";
return 0;
}
diff --git a/tools/clang-format/clang-format-test.el b/tools/clang-format/clang-format-test.el
new file mode 100644
index 000000000000..0e1f4dde406b
--- /dev/null
+++ b/tools/clang-format/clang-format-test.el
@@ -0,0 +1,126 @@
+;;; clang-format-test.el --- unit tests for clang-format.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2017 Google Inc.
+
+;; Author: Philipp Stephani <phst@google.com>
+
+;; This file is distributed under the University of Illinois Open Source
+;; License. See LICENSE.TXT for details.
+
+;;; Commentary:
+
+;; Unit tests for clang-format.el.
+
+;;; Code:
+
+(require 'clang-format)
+
+(require 'cl-lib)
+(require 'ert)
+(require 'pcase)
+
+(ert-deftest clang-format-buffer--buffer-encoding ()
+ "Tests that encoded text is handled properly."
+ (cl-letf* ((call-process-args nil)
+ ((symbol-function 'call-process-region)
+ (lambda (&rest args)
+ (push args call-process-args)
+ (pcase-exhaustive args
+ (`(,_start ,_end ,_program ,_delete (,stdout ,_stderr)
+ ,_display . ,_args)
+ (with-current-buffer stdout
+ (insert "<?xml version='1.0'?>
+<replacements xml:space='preserve' incomplete_format='false'>
+<replacement offset='4' length='0'> </replacement>
+<replacement offset='10' length='0'> </replacement>
+</replacements>
+"))
+ 0)))))
+ (with-temp-buffer
+ (let ((buffer-file-name "foo.cpp")
+ (buffer-file-coding-system 'utf-8-with-signature-dos)
+ (default-process-coding-system 'latin-1-unix))
+ (insert "ä =ö;\nü= ß;\n")
+ (goto-char (point-min))
+ (end-of-line)
+ (clang-format-buffer))
+ (should (equal (buffer-string) "ä = ö;\nü = ß;\n"))
+ (should (eolp))
+ (should (equal (buffer-substring (point) (point-max))
+ "\nü = ß;\n")))
+ (should-not (cdr call-process-args))
+ (pcase-exhaustive call-process-args
+ (`((,start ,end ,_program ,delete (,_stdout ,_stderr) ,display . ,args))
+ (should-not start)
+ (should-not end)
+ (should-not delete)
+ (should-not display)
+ (should (equal args
+ '("-output-replacements-xml" "-assume-filename" "foo.cpp"
+ "-style" "file"
+ ;; Beginning of buffer, no byte-order mark.
+ "-offset" "0"
+ ;; We have two lines with 2×2 bytes for the umlauts,
+ ;; 1 byte for the line ending, and 3 bytes for the
+ ;; other ASCII characters each.
+ "-length" "16"
+ ;; Length of a single line (without line ending).
+ "-cursor" "7")))))))
+
+(ert-deftest clang-format-buffer--process-encoding ()
+ "Tests that text is sent to the clang-format process in the
+right encoding."
+ (cl-letf* ((hexdump (executable-find "hexdump"))
+ (original-call-process-region
+ (symbol-function 'call-process-region))
+ (call-process-inputs nil)
+ ;; We redirect the input to hexdump so that we have guaranteed
+ ;; ASCII output.
+ ((symbol-function 'call-process-region)
+ (lambda (&rest args)
+ (pcase-exhaustive args
+ (`(,start ,end ,_program ,_delete (,stdout ,_stderr)
+ ,_display . ,_args)
+ (with-current-buffer stdout
+ (insert "<?xml version='1.0'?>
+<replacements xml:space='preserve' incomplete_format='false'>
+</replacements>
+"))
+ (let ((stdin (current-buffer)))
+ (with-temp-buffer
+ (prog1
+ (let ((stdout (current-buffer)))
+ (with-current-buffer stdin
+ (funcall original-call-process-region
+ start end hexdump nil stdout nil
+ "-v" "-e" "/1 \"%02x \"")))
+ (push (buffer-string) call-process-inputs)))))))))
+ (skip-unless hexdump)
+ (with-temp-buffer
+ (let ((buffer-file-name "foo.cpp")
+ (buffer-file-coding-system 'utf-8-with-signature-dos)
+ (default-process-coding-system 'latin-1-unix))
+ (insert "ä\n")
+ (clang-format-buffer))
+ (should (equal (buffer-string) "ä\n"))
+ (should (eobp)))
+ (should (equal call-process-inputs '("c3 a4 0a ")))))
+
+(ert-deftest clang-format-buffer--end-to-end ()
+ "End-to-end test for ‘clang-format-buffer’.
+Actually calls the clang-format binary."
+ (skip-unless (file-executable-p clang-format-executable))
+ (with-temp-buffer
+ (let ((buffer-file-name "foo.cpp")
+ (buffer-file-coding-system 'utf-8-with-signature-dos)
+ (default-process-coding-system 'latin-1-unix))
+ (insert "ä =ö;\nü= ß;\n")
+ (goto-char (point-min))
+ (end-of-line)
+ (clang-format-buffer))
+ (should (equal (buffer-string) "ä = ö;\nü = ß;\n"))
+ (should (eolp))
+ (should (equal (buffer-substring (point) (point-max))
+ "\nü = ß;\n"))))
+
+;;; clang-format-test.el ends here
diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el
index 0ac2da3ad29a..aa9c3ff4ca0b 100644
--- a/tools/clang-format/clang-format.el
+++ b/tools/clang-format/clang-format.el
@@ -95,9 +95,10 @@ of the buffer."
(defun clang-format--replace (offset length &optional text)
"Replace the region defined by OFFSET and LENGTH with TEXT.
OFFSET and LENGTH are measured in bytes, not characters. OFFSET
-is a zero-based file offset."
- (let ((start (clang-format--filepos-to-bufferpos offset 'exact))
- (end (clang-format--filepos-to-bufferpos (+ offset length) 'exact)))
+is a zero-based file offset, assuming ‘utf-8-unix’ coding."
+ (let ((start (clang-format--filepos-to-bufferpos offset 'exact 'utf-8-unix))
+ (end (clang-format--filepos-to-bufferpos (+ offset length) 'exact
+ 'utf-8-unix)))
(goto-char start)
(delete-region start end)
(when text
@@ -130,11 +131,18 @@ is no active region. If no style is given uses `clang-format-style'."
(unless style
(setq style clang-format-style))
- (let ((file-start (clang-format--bufferpos-to-filepos start 'approximate))
- (file-end (clang-format--bufferpos-to-filepos end 'approximate))
- (cursor (clang-format--bufferpos-to-filepos (point) 'exact))
+ (let ((file-start (clang-format--bufferpos-to-filepos start 'approximate
+ 'utf-8-unix))
+ (file-end (clang-format--bufferpos-to-filepos end 'approximate
+ 'utf-8-unix))
+ (cursor (clang-format--bufferpos-to-filepos (point) 'exact 'utf-8-unix))
(temp-buffer (generate-new-buffer " *clang-format-temp*"))
- (temp-file (make-temp-file "clang-format")))
+ (temp-file (make-temp-file "clang-format"))
+ ;; Output is XML, which is always UTF-8. Input encoding should match
+ ;; the encoding used to convert between buffer and file positions,
+ ;; otherwise the offsets calculated above are off. For simplicity, we
+ ;; always use ‘utf-8-unix’ and ignore the buffer coding system.
+ (default-process-coding-system '(utf-8-unix . utf-8-unix)))
(unwind-protect
(let ((status (call-process-region
nil nil clang-format-executable
@@ -164,7 +172,8 @@ is no active region. If no style is given uses `clang-format-style'."
(dolist (rpl replacements)
(apply #'clang-format--replace rpl)))
(when cursor
- (goto-char (clang-format--filepos-to-bufferpos cursor 'exact)))
+ (goto-char (clang-format--filepos-to-bufferpos cursor 'exact
+ 'utf-8-unix)))
(if incomplete-format
(message "(clang-format: incomplete (syntax errors)%s)" stderr)
(message "(clang-format: success%s)" stderr))))
diff --git a/tools/clang-import-test/clang-import-test.cpp b/tools/clang-import-test/clang-import-test.cpp
index 33190af4bf45..d7ab18478c32 100644
--- a/tools/clang-import-test/clang-import-test.cpp
+++ b/tools/clang-import-test/clang-import-test.cpp
@@ -9,6 +9,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTImporter.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExternalASTMerger.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
@@ -189,61 +191,18 @@ std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
} // end namespace
namespace {
-class TestExternalASTSource : public ExternalASTSource {
-private:
- llvm::ArrayRef<std::unique_ptr<CompilerInstance>> ImportCIs;
- std::map<CompilerInstance *, std::unique_ptr<ASTImporter>> ForwardImporters;
- std::map<CompilerInstance *, std::unique_ptr<ASTImporter>> ReverseImporters;
-
-public:
- TestExternalASTSource(
- CompilerInstance &ExpressionCI,
- llvm::ArrayRef<std::unique_ptr<CompilerInstance>> ImportCIs)
- : ImportCIs(ImportCIs) {
- for (const std::unique_ptr<CompilerInstance> &ImportCI : ImportCIs) {
- ForwardImporters[ImportCI.get()] = llvm::make_unique<ASTImporter>(
- ExpressionCI.getASTContext(), ExpressionCI.getFileManager(),
- ImportCI->getASTContext(), ImportCI->getFileManager(),
- /*MinimalImport=*/true);
- ReverseImporters[ImportCI.get()] = llvm::make_unique<ASTImporter>(
- ImportCI->getASTContext(), ImportCI->getFileManager(),
- ExpressionCI.getASTContext(), ExpressionCI.getFileManager(),
- /*MinimalImport=*/true);
- }
- }
-
- bool FindExternalVisibleDeclsByName(const DeclContext *DC,
- DeclarationName Name) override {
- llvm::SmallVector<NamedDecl *, 1> Decls;
-
- if (isa<TranslationUnitDecl>(DC)) {
- for (const std::unique_ptr<CompilerInstance> &I : ImportCIs) {
- DeclarationName FromName = ReverseImporters[I.get()]->Import(Name);
- DeclContextLookupResult Result =
- I->getASTContext().getTranslationUnitDecl()->lookup(FromName);
- for (NamedDecl *FromD : Result) {
- NamedDecl *D =
- llvm::cast<NamedDecl>(ForwardImporters[I.get()]->Import(FromD));
- Decls.push_back(D);
- }
- }
- }
- if (Decls.empty()) {
- return false;
- } else {
- SetExternalVisibleDeclsForName(DC, Name, Decls);
- return true;
- }
- }
-};
-
+
void AddExternalSource(
CompilerInstance &CI,
llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
- ASTContext &AST = CI.getASTContext();
- auto ES = llvm::make_unique<TestExternalASTSource>(CI, Imports);
- AST.setExternalSource(ES.release());
- AST.getTranslationUnitDecl()->setHasExternalVisibleStorage();
+ ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()});
+ llvm::SmallVector<ExternalASTMerger::ImporterEndpoint, 3> Sources;
+ for (const std::unique_ptr<CompilerInstance> &CI : Imports) {
+ Sources.push_back({CI->getASTContext(), CI->getFileManager()});
+ }
+ auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
+ CI.getASTContext().setExternalSource(ES.release());
+ CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
}
llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
@@ -292,6 +251,7 @@ Parse(const std::string &Path,
return std::move(CI);
}
}
+
} // end namespace
int main(int argc, const char **argv) {
diff --git a/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
index 20988b48ede1..49cdd9546689 100644
--- a/tools/clang-offload-bundler/ClangOffloadBundler.cpp
+++ b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
@@ -412,7 +412,7 @@ class ObjectFileHandler final : public FileHandler {
/// read from the buffers.
unsigned NumberOfProcessedInputs = 0;
- /// LLVM context used to to create the auxiliar modules.
+ /// LLVM context used to to create the auxiliary modules.
LLVMContext VMContext;
/// LLVM module used to create an object with all the bundle
@@ -514,7 +514,10 @@ public:
// Dump the contents of the temporary file if that was requested.
if (DumpTemporaryFiles) {
errs() << ";\n; Object file bundler IR file.\n;\n";
- AuxModule.get()->dump();
+ AuxModule.get()->print(errs(), nullptr,
+ /*ShouldPreserveUseListOrder=*/false,
+ /*IsForDebug=*/true);
+ errs() << '\n';
}
// Find clang in order to create the bundle binary.
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index f6e26fa11f41..901b6d62e465 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -61,7 +61,7 @@ add_dependencies(clang clang-headers)
if(NOT CLANG_LINKS_TO_CREATE)
set(CLANG_LINKS_TO_CREATE clang++ clang-cl clang-cpp)
- if (WIN32)
+ if (MSVC)
list(APPEND CLANG_LINKS_TO_CREATE ../msbuild-bin/cl)
endif()
endif()
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 263751346b80..2fa8edb81ae4 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -212,13 +212,11 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Frontend Options
if (Args.hasArg(OPT_INPUT)) {
bool First = true;
- for (arg_iterator it = Args.filtered_begin(OPT_INPUT),
- ie = Args.filtered_end();
- it != ie; ++it, First = false) {
- const Arg *A = it;
- if (First)
+ for (const Arg *A : Args.filtered(OPT_INPUT)) {
+ if (First) {
Opts.InputFile = A->getValue();
- else {
+ First = false;
+ } else {
Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
Success = false;
}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 61613028625b..626d006ac0d8 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -460,8 +460,9 @@ int main(int argc_, const char **argv_) {
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
// Force a crash to test the diagnostics.
- if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) {
- Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH";
+ if (TheDriver.GenReproducer) {
+ Diags.Report(diag::err_drv_force_crash)
+ << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
// Pretend that every command failed.
FailingCommands.clear();
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 67fa2aea1d45..216322b9f936 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1265,10 +1265,11 @@ bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
switch (Name.getName().getNameKind()) {
case clang::DeclarationName::Identifier:
case clang::DeclarationName::CXXLiteralOperatorName:
+ case clang::DeclarationName::CXXDeductionGuideName:
case clang::DeclarationName::CXXOperatorName:
case clang::DeclarationName::CXXUsingDirective:
return false;
-
+
case clang::DeclarationName::CXXConstructorName:
case clang::DeclarationName::CXXDestructorName:
case clang::DeclarationName::CXXConversionFunctionName:
@@ -1492,7 +1493,6 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
#define BUILTIN_TYPE(Id, SingletonId)
#define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
@@ -1640,6 +1640,15 @@ bool CursorVisitor::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
return Visit(TL.getOriginalLoc());
}
+bool CursorVisitor::VisitDeducedTemplateSpecializationTypeLoc(
+ DeducedTemplateSpecializationTypeLoc TL) {
+ if (VisitTemplateName(TL.getTypePtr()->getTemplateName(),
+ TL.getTemplateNameLoc()))
+ return true;
+
+ return false;
+}
+
bool CursorVisitor::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
// Visit the template name.
@@ -2104,6 +2113,7 @@ void OMPClauseEnqueue::VisitOMPClauseWithPostUpdate(
}
void OMPClauseEnqueue::VisitOMPIfClause(const OMPIfClause *C) {
+ VisitOMPClauseWithPreInit(C);
Visitor->AddStmt(C->getCondition());
}
@@ -2112,6 +2122,7 @@ void OMPClauseEnqueue::VisitOMPFinalClause(const OMPFinalClause *C) {
}
void OMPClauseEnqueue::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) {
+ VisitOMPClauseWithPreInit(C);
Visitor->AddStmt(C->getNumThreads());
}
@@ -2167,10 +2178,12 @@ void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) {
}
void OMPClauseEnqueue::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) {
+ VisitOMPClauseWithPreInit(C);
Visitor->AddStmt(C->getNumTeams());
}
void OMPClauseEnqueue::VisitOMPThreadLimitClause(const OMPThreadLimitClause *C) {
+ VisitOMPClauseWithPreInit(C);
Visitor->AddStmt(C->getThreadLimit());
}
@@ -5769,6 +5782,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::OMPCapturedExpr:
case Decl::Label: // FIXME: Is this right??
case Decl::ClassScopeFunctionSpecialization:
+ case Decl::CXXDeductionGuide:
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::OMPDeclareReduction:
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index ca68bc1cd28e..c2b4c0bcb072 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -270,10 +270,6 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Source manager, used for diagnostics.
IntrusiveRefCntPtr<SourceManager> SourceMgr;
- /// \brief Temporary files that should be removed once we have finished
- /// with the code-completion results.
- std::vector<std::string> TemporaryFiles;
-
/// \brief Temporary buffers that will be deleted once we have finished with
/// the code-completion results.
SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers;
@@ -320,7 +316,8 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
: CXCodeCompleteResults(), DiagOpts(new DiagnosticOptions),
Diag(new DiagnosticsEngine(
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)),
- FileMgr(FileMgr), SourceMgr(new SourceManager(*Diag, *FileMgr)),
+ FileMgr(std::move(FileMgr)),
+ SourceMgr(new SourceManager(*Diag, *this->FileMgr)),
CodeCompletionAllocator(
std::make_shared<clang::GlobalCodeCompletionAllocator>()),
Contexts(CXCompletionContext_Unknown),
@@ -334,8 +331,6 @@ AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
llvm::DeleteContainerPointers(DiagnosticsWrappers);
delete [] Results;
- for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
- llvm::sys::fs::remove(TemporaryFiles[I]);
for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I)
delete TemporaryBuffers[I];
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 8731ca65c423..c19aa65ac622 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -231,6 +231,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::TypeTraitExprClass:
case Stmt::CoroutineBodyStmtClass:
case Stmt::CoawaitExprClass:
+ case Stmt::DependentCoawaitExprClass:
case Stmt::CoreturnStmtClass:
case Stmt::CoyieldExprClass:
case Stmt::CXXBindTemporaryExprClass:
diff --git a/tools/libclang/CXIndexDataConsumer.cpp b/tools/libclang/CXIndexDataConsumer.cpp
index cb8aebfd0c48..5d9776be3b6c 100644
--- a/tools/libclang/CXIndexDataConsumer.cpp
+++ b/tools/libclang/CXIndexDataConsumer.cpp
@@ -1294,6 +1294,7 @@ static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage
case SymbolKind::Constructor: return CXIdxEntity_CXXConstructor;
case SymbolKind::Destructor: return CXIdxEntity_CXXDestructor;
case SymbolKind::ConversionFunction: return CXIdxEntity_CXXConversionFunction;
+ case SymbolKind::Parameter: return CXIdxEntity_Variable;
}
llvm_unreachable("invalid symbol kind");
}
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 66caf340d195..16e993e2ac01 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -48,6 +48,7 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
BTCASE(Long);
BTCASE(LongLong);
BTCASE(Int128);
+ BTCASE(Half);
BTCASE(Float);
BTCASE(Double);
BTCASE(LongDouble);
@@ -452,7 +453,8 @@ try_again:
break;
case Type::Auto:
- TP = cast<AutoType>(TP)->getDeducedType().getTypePtrOrNull();
+ case Type::DeducedTemplateSpecialization:
+ TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull();
if (TP)
goto try_again;
break;
@@ -502,6 +504,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(Long);
TKIND(LongLong);
TKIND(Int128);
+ TKIND(Half);
TKIND(Float);
TKIND(Double);
TKIND(LongDouble);
@@ -1036,3 +1039,12 @@ CXType clang_Type_getNamedType(CXType CT){
return MakeCXType(QualType(), GetTU(CT));
}
+
+unsigned clang_Type_isTransparentTagTypedef(CXType TT){
+ QualType T = GetQualType(TT);
+ if (auto *TT = dyn_cast_or_null<TypedefType>(T.getTypePtrOrNull())) {
+ if (auto *D = TT->getDecl())
+ return D->isTransparentTag();
+ }
+ return false;
+}
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 222cb678395e..38ecedae3cd4 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -88,6 +88,7 @@ clang_Type_getTemplateArgumentAsType
clang_Type_getCXXRefQualifier
clang_Type_visitFields
clang_Type_getNamedType
+clang_Type_isTransparentTagTypedef
clang_VerbatimBlockLineComment_getText
clang_VerbatimLineComment_getText
clang_HTMLTagComment_getAsString
diff --git a/tools/scan-build-py/bin/analyze-build b/tools/scan-build-py/bin/analyze-build
index 2cc9676fd546..991cff0658f2 100644
--- a/tools/scan-build-py/bin/analyze-build
+++ b/tools/scan-build-py/bin/analyze-build
@@ -13,5 +13,5 @@ import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
-from libscanbuild.analyze import analyze_build_main
-sys.exit(analyze_build_main(this_dir, False))
+from libscanbuild.analyze import analyze_build
+sys.exit(analyze_build())
diff --git a/tools/scan-build-py/bin/analyze-build.bat b/tools/scan-build-py/bin/analyze-build.bat
deleted file mode 100644
index 05d81ddfda4d..000000000000
--- a/tools/scan-build-py/bin/analyze-build.bat
+++ /dev/null
@@ -1 +0,0 @@
-python %~dp0analyze-build %*
diff --git a/tools/scan-build-py/bin/analyze-c++ b/tools/scan-build-py/bin/analyze-c++
index 15186d89aa3f..df1012dee57e 100644
--- a/tools/scan-build-py/bin/analyze-c++
+++ b/tools/scan-build-py/bin/analyze-c++
@@ -10,5 +10,5 @@ import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
-from libscanbuild.analyze import analyze_build_wrapper
-sys.exit(analyze_build_wrapper(True))
+from libscanbuild.analyze import analyze_compiler_wrapper
+sys.exit(analyze_compiler_wrapper())
diff --git a/tools/scan-build-py/bin/analyze-c++.bat b/tools/scan-build-py/bin/analyze-c++.bat
deleted file mode 100644
index f57032f60bd4..000000000000
--- a/tools/scan-build-py/bin/analyze-c++.bat
+++ /dev/null
@@ -1 +0,0 @@
-python %~dp0analyze-c++ %*
diff --git a/tools/scan-build-py/bin/analyze-cc b/tools/scan-build-py/bin/analyze-cc
index 55519fb7b11d..df1012dee57e 100644
--- a/tools/scan-build-py/bin/analyze-cc
+++ b/tools/scan-build-py/bin/analyze-cc
@@ -10,5 +10,5 @@ import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
-from libscanbuild.analyze import analyze_build_wrapper
-sys.exit(analyze_build_wrapper(False))
+from libscanbuild.analyze import analyze_compiler_wrapper
+sys.exit(analyze_compiler_wrapper())
diff --git a/tools/scan-build-py/bin/analyze-cc.bat b/tools/scan-build-py/bin/analyze-cc.bat
deleted file mode 100644
index 41cd8f622eb2..000000000000
--- a/tools/scan-build-py/bin/analyze-cc.bat
+++ /dev/null
@@ -1 +0,0 @@
-python %~dp0analyze-cc %*
diff --git a/tools/scan-build-py/bin/intercept-build b/tools/scan-build-py/bin/intercept-build
index 164f2e68be93..2c3a26ecdddc 100644
--- a/tools/scan-build-py/bin/intercept-build
+++ b/tools/scan-build-py/bin/intercept-build
@@ -13,5 +13,5 @@ import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
-from libscanbuild.intercept import intercept_build_main
-sys.exit(intercept_build_main(this_dir))
+from libscanbuild.intercept import intercept_build
+sys.exit(intercept_build())
diff --git a/tools/scan-build-py/bin/intercept-build.bat b/tools/scan-build-py/bin/intercept-build.bat
deleted file mode 100644
index 5c824635dfe4..000000000000
--- a/tools/scan-build-py/bin/intercept-build.bat
+++ /dev/null
@@ -1 +0,0 @@
-python %~dp0intercept-build %*
diff --git a/tools/scan-build-py/bin/intercept-c++ b/tools/scan-build-py/bin/intercept-c++
index fc422287f84b..67e076f39e4b 100644
--- a/tools/scan-build-py/bin/intercept-c++
+++ b/tools/scan-build-py/bin/intercept-c++
@@ -10,5 +10,5 @@ import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
-from libscanbuild.intercept import intercept_build_wrapper
-sys.exit(intercept_build_wrapper(True))
+from libscanbuild.intercept import intercept_compiler_wrapper
+sys.exit(intercept_compiler_wrapper())
diff --git a/tools/scan-build-py/bin/intercept-c++.bat b/tools/scan-build-py/bin/intercept-c++.bat
deleted file mode 100644
index abbd4b177e0f..000000000000
--- a/tools/scan-build-py/bin/intercept-c++.bat
+++ /dev/null
@@ -1 +0,0 @@
-python %~dp0intercept-c++ %*
diff --git a/tools/scan-build-py/bin/intercept-cc b/tools/scan-build-py/bin/intercept-cc
index 69d57aaae107..67e076f39e4b 100644
--- a/tools/scan-build-py/bin/intercept-cc
+++ b/tools/scan-build-py/bin/intercept-cc
@@ -10,5 +10,5 @@ import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
-from libscanbuild.intercept import intercept_build_wrapper
-sys.exit(intercept_build_wrapper(False))
+from libscanbuild.intercept import intercept_compiler_wrapper
+sys.exit(intercept_compiler_wrapper())
diff --git a/tools/scan-build-py/bin/intercept-cc.bat b/tools/scan-build-py/bin/intercept-cc.bat
deleted file mode 100644
index 23cbd8d22ca6..000000000000
--- a/tools/scan-build-py/bin/intercept-cc.bat
+++ /dev/null
@@ -1 +0,0 @@
-python %~dp0intercept-cc %*
diff --git a/tools/scan-build-py/bin/scan-build b/tools/scan-build-py/bin/scan-build
index 601fe89fc30d..f0f34695b0f1 100644
--- a/tools/scan-build-py/bin/scan-build
+++ b/tools/scan-build-py/bin/scan-build
@@ -13,5 +13,5 @@ import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
-from libscanbuild.analyze import analyze_build_main
-sys.exit(analyze_build_main(this_dir, True))
+from libscanbuild.analyze import scan_build
+sys.exit(scan_build())
diff --git a/tools/scan-build-py/bin/scan-build.bat b/tools/scan-build-py/bin/scan-build.bat
deleted file mode 100644
index 8caf240a2f0b..000000000000
--- a/tools/scan-build-py/bin/scan-build.bat
+++ /dev/null
@@ -1 +0,0 @@
-python %~dp0scan-build %*
diff --git a/tools/scan-build-py/libear/__init__.py b/tools/scan-build-py/libear/__init__.py
index 3e1c13cf2bfe..421e2e74f023 100644
--- a/tools/scan-build-py/libear/__init__.py
+++ b/tools/scan-build-py/libear/__init__.py
@@ -207,9 +207,9 @@ class Configure(object):
if m:
key = m.group(1)
if key not in definitions or not definitions[key]:
- return '/* #undef {} */\n'.format(key)
+ return '/* #undef {0} */{1}'.format(key, os.linesep)
else:
- return '#define {}\n'.format(key)
+ return '#define {0}{1}'.format(key, os.linesep)
return line
with open(template, 'r') as src_handle:
diff --git a/tools/scan-build-py/libscanbuild/__init__.py b/tools/scan-build-py/libscanbuild/__init__.py
index c020b4e4345d..800926ebb6f2 100644
--- a/tools/scan-build-py/libscanbuild/__init__.py
+++ b/tools/scan-build-py/libscanbuild/__init__.py
@@ -3,10 +3,21 @@
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
-"""
-This module responsible to run the Clang static analyzer against any build
-and generate reports.
-"""
+""" This module is a collection of methods commonly used in this project. """
+import collections
+import functools
+import json
+import logging
+import os
+import os.path
+import re
+import shlex
+import subprocess
+import sys
+
+ENVIRONMENT_KEY = 'INTERCEPT_BUILD'
+
+Execution = collections.namedtuple('Execution', ['pid', 'cwd', 'cmd'])
def duplicate_check(method):
@@ -30,44 +41,89 @@ def duplicate_check(method):
return predicate
-def tempdir():
- """ Return the default temorary directory. """
-
- from os import getenv
- return getenv('TMPDIR', getenv('TEMP', getenv('TMP', '/tmp')))
-
-
-def initialize_logging(verbose_level):
- """ Output content controlled by the verbosity level. """
-
- import sys
- import os.path
- import logging
+def run_build(command, *args, **kwargs):
+ """ Run and report build command execution
+
+ :param command: array of tokens
+ :return: exit code of the process
+ """
+ environment = kwargs.get('env', os.environ)
+ logging.debug('run build %s, in environment: %s', command, environment)
+ exit_code = subprocess.call(command, *args, **kwargs)
+ logging.debug('build finished with exit code: %d', exit_code)
+ return exit_code
+
+
+def run_command(command, cwd=None):
+ """ Run a given command and report the execution.
+
+ :param command: array of tokens
+ :param cwd: the working directory where the command will be executed
+ :return: output of the command
+ """
+ def decode_when_needed(result):
+ """ check_output returns bytes or string depend on python version """
+ return result.decode('utf-8') if isinstance(result, bytes) else result
+
+ try:
+ directory = os.path.abspath(cwd) if cwd else os.getcwd()
+ logging.debug('exec command %s in %s', command, directory)
+ output = subprocess.check_output(command,
+ cwd=directory,
+ stderr=subprocess.STDOUT)
+ return decode_when_needed(output).splitlines()
+ except subprocess.CalledProcessError as ex:
+ ex.output = decode_when_needed(ex.output).splitlines()
+ raise ex
+
+
+def reconfigure_logging(verbose_level):
+ """ Reconfigure logging level and format based on the verbose flag.
+
+ :param verbose_level: number of `-v` flags received by the command
+ :return: no return value
+ """
+ # Exit when nothing to do.
+ if verbose_level == 0:
+ return
+
+ root = logging.getLogger()
+ # Tune logging level.
level = logging.WARNING - min(logging.WARNING, (10 * verbose_level))
-
+ root.setLevel(level)
+ # Be verbose with messages.
if verbose_level <= 3:
- fmt_string = '{0}: %(levelname)s: %(message)s'
+ fmt_string = '%(name)s: %(levelname)s: %(message)s'
else:
- fmt_string = '{0}: %(levelname)s: %(funcName)s: %(message)s'
-
- program = os.path.basename(sys.argv[0])
- logging.basicConfig(format=fmt_string.format(program), level=level)
+ fmt_string = '%(name)s: %(levelname)s: %(funcName)s: %(message)s'
+ handler = logging.StreamHandler(sys.stdout)
+ handler.setFormatter(logging.Formatter(fmt=fmt_string))
+ root.handlers = [handler]
def command_entry_point(function):
- """ Decorator for command entry points. """
+ """ Decorator for command entry methods.
+
+ The decorator initialize/shutdown logging and guard on programming
+ errors (catch exceptions).
- import functools
- import logging
+ The decorated method can have arbitrary parameters, the return value will
+ be the exit code of the process. """
@functools.wraps(function)
def wrapper(*args, **kwargs):
+ """ Do housekeeping tasks and execute the wrapped method. """
- exit_code = 127
try:
- exit_code = function(*args, **kwargs)
+ logging.basicConfig(format='%(name)s: %(message)s',
+ level=logging.WARNING,
+ stream=sys.stdout)
+ # This hack to get the executable name as %(name).
+ logging.getLogger().name = os.path.basename(sys.argv[0])
+ return function(*args, **kwargs)
except KeyboardInterrupt:
- logging.warning('Keyboard interupt')
+ logging.warning('Keyboard interrupt')
+ return 130 # Signal received exit code for bash.
except Exception:
logging.exception('Internal error.')
if logging.getLogger().isEnabledFor(logging.DEBUG):
@@ -75,8 +131,75 @@ def command_entry_point(function):
"to the bug report")
else:
logging.error("Please run this command again and turn on "
- "verbose mode (add '-vvv' as argument).")
+ "verbose mode (add '-vvvv' as argument).")
+ return 64 # Some non used exit code for internal errors.
finally:
- return exit_code
+ logging.shutdown()
return wrapper
+
+
+def compiler_wrapper(function):
+ """ Implements compiler wrapper base functionality.
+
+ A compiler wrapper executes the real compiler, then implement some
+ functionality, then returns with the real compiler exit code.
+
+ :param function: the extra functionality what the wrapper want to
+ do on top of the compiler call. If it throws exception, it will be
+ caught and logged.
+ :return: the exit code of the real compiler.
+
+ The :param function: will receive the following arguments:
+
+ :param result: the exit code of the compilation.
+ :param execution: the command executed by the wrapper. """
+
+ def is_cxx_compiler():
+ """ Find out was it a C++ compiler call. Compiler wrapper names
+ contain the compiler type. C++ compiler wrappers ends with `c++`,
+ but might have `.exe` extension on windows. """
+
+ wrapper_command = os.path.basename(sys.argv[0])
+ return re.match(r'(.+)c\+\+(.*)', wrapper_command)
+
+ def run_compiler(executable):
+ """ Execute compilation with the real compiler. """
+
+ command = executable + sys.argv[1:]
+ logging.debug('compilation: %s', command)
+ result = subprocess.call(command)
+ logging.debug('compilation exit code: %d', result)
+ return result
+
+ # Get relevant parameters from environment.
+ parameters = json.loads(os.environ[ENVIRONMENT_KEY])
+ reconfigure_logging(parameters['verbose'])
+ # Execute the requested compilation. Do crash if anything goes wrong.
+ cxx = is_cxx_compiler()
+ compiler = parameters['cxx'] if cxx else parameters['cc']
+ result = run_compiler(compiler)
+ # Call the wrapped method and ignore it's return value.
+ try:
+ call = Execution(
+ pid=os.getpid(),
+ cwd=os.getcwd(),
+ cmd=['c++' if cxx else 'cc'] + sys.argv[1:])
+ function(result, call)
+ except:
+ logging.exception('Compiler wrapper failed complete.')
+ finally:
+ # Always return the real compiler exit code.
+ return result
+
+
+def wrapper_environment(args):
+ """ Set up environment for interpose compiler wrapper."""
+
+ return {
+ ENVIRONMENT_KEY: json.dumps({
+ 'verbose': args.verbose,
+ 'cc': shlex.split(args.cc),
+ 'cxx': shlex.split(args.cxx)
+ })
+ }
diff --git a/tools/scan-build-py/libscanbuild/analyze.py b/tools/scan-build-py/libscanbuild/analyze.py
index 244c34b75837..a09c72389d76 100644
--- a/tools/scan-build-py/libscanbuild/analyze.py
+++ b/tools/scan-build-py/libscanbuild/analyze.py
@@ -11,72 +11,75 @@ To run the static analyzer against a build is done in multiple steps:
-- Analyze: run the analyzer against the captured commands,
-- Report: create a cover report from the analyzer outputs. """
-import sys
import re
import os
import os.path
import json
-import argparse
import logging
-import subprocess
import multiprocessing
-from libscanbuild import initialize_logging, tempdir, command_entry_point
-from libscanbuild.runner import run
+import tempfile
+import functools
+import subprocess
+import contextlib
+import datetime
+
+from libscanbuild import command_entry_point, compiler_wrapper, \
+ wrapper_environment, run_build, run_command
+from libscanbuild.arguments import parse_args_for_scan_build, \
+ parse_args_for_analyze_build
from libscanbuild.intercept import capture
-from libscanbuild.report import report_directory, document
-from libscanbuild.clang import get_checkers
-from libscanbuild.compilation import split_command
+from libscanbuild.report import document
+from libscanbuild.compilation import split_command, classify_source, \
+ compiler_language
+from libscanbuild.clang import get_version, get_arguments
+from libscanbuild.shell import decode
-__all__ = ['analyze_build_main', 'analyze_build_wrapper']
+__all__ = ['scan_build', 'analyze_build', 'analyze_compiler_wrapper']
COMPILER_WRAPPER_CC = 'analyze-cc'
COMPILER_WRAPPER_CXX = 'analyze-c++'
@command_entry_point
-def analyze_build_main(bin_dir, from_build_command):
- """ Entry point for 'analyze-build' and 'scan-build'. """
-
- parser = create_parser(from_build_command)
- args = parser.parse_args()
- validate(parser, args, from_build_command)
-
- # setup logging
- initialize_logging(args.verbose)
- logging.debug('Parsed arguments: %s', args)
-
- with report_directory(args.output, args.keep_empty) as target_dir:
- if not from_build_command:
- # run analyzer only and generate cover report
- run_analyzer(args, target_dir)
- number_of_bugs = document(args, target_dir, True)
- return number_of_bugs if args.status_bugs else 0
- elif args.intercept_first:
- # run build command and capture compiler executions
- exit_code = capture(args, bin_dir)
- # next step to run the analyzer against the captured commands
+def scan_build():
+ """ Entry point for scan-build command. """
+
+ args = parse_args_for_scan_build()
+ # will re-assign the report directory as new output
+ with report_directory(args.output, args.keep_empty) as args.output:
+ # Run against a build command. there are cases, when analyzer run
+ # is not required. But we need to set up everything for the
+ # wrappers, because 'configure' needs to capture the CC/CXX values
+ # for the Makefile.
+ if args.intercept_first:
+ # Run build command with intercept module.
+ exit_code = capture(args)
+ # Run the analyzer against the captured commands.
if need_analyzer(args.build):
- run_analyzer(args, target_dir)
- # cover report generation and bug counting
- number_of_bugs = document(args, target_dir, True)
- # remove the compilation database when it was not requested
- if os.path.exists(args.cdb):
- os.unlink(args.cdb)
- # set exit status as it was requested
- return number_of_bugs if args.status_bugs else exit_code
- else:
- return exit_code
+ run_analyzer_parallel(args)
else:
- # run the build command with compiler wrappers which
- # execute the analyzer too. (interposition)
- environment = setup_environment(args, target_dir, bin_dir)
- logging.debug('run build in environment: %s', environment)
- exit_code = subprocess.call(args.build, env=environment)
- logging.debug('build finished with exit code: %d', exit_code)
- # cover report generation and bug counting
- number_of_bugs = document(args, target_dir, False)
- # set exit status as it was requested
- return number_of_bugs if args.status_bugs else exit_code
+ # Run build command and analyzer with compiler wrappers.
+ environment = setup_environment(args)
+ exit_code = run_build(args.build, env=environment)
+ # Cover report generation and bug counting.
+ number_of_bugs = document(args)
+ # Set exit status as it was requested.
+ return number_of_bugs if args.status_bugs else exit_code
+
+
+@command_entry_point
+def analyze_build():
+ """ Entry point for analyze-build command. """
+
+ args = parse_args_for_analyze_build()
+ # will re-assign the report directory as new output
+ with report_directory(args.output, args.keep_empty) as args.output:
+ # Run the analyzer against a compilation db.
+ run_analyzer_parallel(args)
+ # Cover report generation and bug counting.
+ number_of_bugs = document(args)
+ # Set exit status as it was requested.
+ return number_of_bugs if args.status_bugs else 0
def need_analyzer(args):
@@ -92,7 +95,7 @@ def need_analyzer(args):
return len(args) and not re.search('configure|autogen', args[0])
-def run_analyzer(args, output_dir):
+def run_analyzer_parallel(args):
""" Runs the analyzer against the given compilation database. """
def exclude(filename):
@@ -102,7 +105,7 @@ def run_analyzer(args, output_dir):
consts = {
'clang': args.clang,
- 'output_dir': output_dir,
+ 'output_dir': args.output,
'output_format': args.output_format,
'output_failures': args.output_failures,
'direct_args': analyzer_params(args),
@@ -124,18 +127,16 @@ def run_analyzer(args, output_dir):
pool.join()
-def setup_environment(args, destination, bin_dir):
+def setup_environment(args):
""" Set up environment for build command to interpose compiler wrapper. """
environment = dict(os.environ)
+ environment.update(wrapper_environment(args))
environment.update({
- 'CC': os.path.join(bin_dir, COMPILER_WRAPPER_CC),
- 'CXX': os.path.join(bin_dir, COMPILER_WRAPPER_CXX),
- 'ANALYZE_BUILD_CC': args.cc,
- 'ANALYZE_BUILD_CXX': args.cxx,
+ 'CC': COMPILER_WRAPPER_CC,
+ 'CXX': COMPILER_WRAPPER_CXX,
'ANALYZE_BUILD_CLANG': args.clang if need_analyzer(args.build) else '',
- 'ANALYZE_BUILD_VERBOSE': 'DEBUG' if args.verbose > 2 else 'WARNING',
- 'ANALYZE_BUILD_REPORT_DIR': destination,
+ 'ANALYZE_BUILD_REPORT_DIR': args.output,
'ANALYZE_BUILD_REPORT_FORMAT': args.output_format,
'ANALYZE_BUILD_REPORT_FAILURES': 'yes' if args.output_failures else '',
'ANALYZE_BUILD_PARAMETERS': ' '.join(analyzer_params(args)),
@@ -144,51 +145,78 @@ def setup_environment(args, destination, bin_dir):
return environment
-def analyze_build_wrapper(cplusplus):
+@command_entry_point
+def analyze_compiler_wrapper():
""" Entry point for `analyze-cc` and `analyze-c++` compiler wrappers. """
- # initialize wrapper logging
- logging.basicConfig(format='analyze: %(levelname)s: %(message)s',
- level=os.getenv('ANALYZE_BUILD_VERBOSE', 'INFO'))
- # execute with real compiler
- compiler = os.getenv('ANALYZE_BUILD_CXX', 'c++') if cplusplus \
- else os.getenv('ANALYZE_BUILD_CC', 'cc')
- compilation = [compiler] + sys.argv[1:]
- logging.info('execute compiler: %s', compilation)
- result = subprocess.call(compilation)
- # exit when it fails, ...
+ return compiler_wrapper(analyze_compiler_wrapper_impl)
+
+
+def analyze_compiler_wrapper_impl(result, execution):
+ """ Implements analyzer compiler wrapper functionality. """
+
+ # don't run analyzer when compilation fails. or when it's not requested.
if result or not os.getenv('ANALYZE_BUILD_CLANG'):
- return result
- # ... and run the analyzer if all went well.
+ return
+
+ # check is it a compilation?
+ compilation = split_command(execution.cmd)
+ if compilation is None:
+ return
+ # collect the needed parameters from environment, crash when missing
+ parameters = {
+ 'clang': os.getenv('ANALYZE_BUILD_CLANG'),
+ 'output_dir': os.getenv('ANALYZE_BUILD_REPORT_DIR'),
+ 'output_format': os.getenv('ANALYZE_BUILD_REPORT_FORMAT'),
+ 'output_failures': os.getenv('ANALYZE_BUILD_REPORT_FAILURES'),
+ 'direct_args': os.getenv('ANALYZE_BUILD_PARAMETERS',
+ '').split(' '),
+ 'force_debug': os.getenv('ANALYZE_BUILD_FORCE_DEBUG'),
+ 'directory': execution.cwd,
+ 'command': [execution.cmd[0], '-c'] + compilation.flags
+ }
+ # call static analyzer against the compilation
+ for source in compilation.files:
+ parameters.update({'file': source})
+ logging.debug('analyzer parameters %s', parameters)
+ current = run(parameters)
+ # display error message from the static analyzer
+ if current is not None:
+ for line in current['error_output']:
+ logging.info(line.rstrip())
+
+
+@contextlib.contextmanager
+def report_directory(hint, keep):
+ """ Responsible for the report directory.
+
+ hint -- could specify the parent directory of the output directory.
+ keep -- a boolean value to keep or delete the empty report directory. """
+
+ stamp_format = 'scan-build-%Y-%m-%d-%H-%M-%S-%f-'
+ stamp = datetime.datetime.now().strftime(stamp_format)
+ parent_dir = os.path.abspath(hint)
+ if not os.path.exists(parent_dir):
+ os.makedirs(parent_dir)
+ name = tempfile.mkdtemp(prefix=stamp, dir=parent_dir)
+
+ logging.info('Report directory created: %s', name)
+
try:
- # check is it a compilation
- compilation = split_command(sys.argv)
- if compilation is None:
- return result
- # collect the needed parameters from environment, crash when missing
- parameters = {
- 'clang': os.getenv('ANALYZE_BUILD_CLANG'),
- 'output_dir': os.getenv('ANALYZE_BUILD_REPORT_DIR'),
- 'output_format': os.getenv('ANALYZE_BUILD_REPORT_FORMAT'),
- 'output_failures': os.getenv('ANALYZE_BUILD_REPORT_FAILURES'),
- 'direct_args': os.getenv('ANALYZE_BUILD_PARAMETERS',
- '').split(' '),
- 'force_debug': os.getenv('ANALYZE_BUILD_FORCE_DEBUG'),
- 'directory': os.getcwd(),
- 'command': [sys.argv[0], '-c'] + compilation.flags
- }
- # call static analyzer against the compilation
- for source in compilation.files:
- parameters.update({'file': source})
- logging.debug('analyzer parameters %s', parameters)
- current = run(parameters)
- # display error message from the static analyzer
- if current is not None:
- for line in current['error_output']:
- logging.info(line.rstrip())
- except Exception:
- logging.exception("run analyzer inside compiler wrapper failed.")
- return result
+ yield name
+ finally:
+ if os.listdir(name):
+ msg = "Run 'scan-view %s' to examine bug reports."
+ keep = True
+ else:
+ if keep:
+ msg = "Report directory '%s' contains no report, but kept."
+ else:
+ msg = "Removing directory '%s' because it contains no report."
+ logging.warning(msg, name)
+
+ if not keep:
+ os.rmdir(name)
def analyzer_params(args):
@@ -238,279 +266,275 @@ def analyzer_params(args):
return prefix_with('-Xclang', result)
-def print_active_checkers(checkers):
- """ Print active checkers to stdout. """
+def require(required):
+ """ Decorator for checking the required values in state.
- for name in sorted(name for name, (_, active) in checkers.items()
- if active):
- print(name)
+ It checks the required attributes in the passed state and stop when
+ any of those is missing. """
+ def decorator(function):
+ @functools.wraps(function)
+ def wrapper(*args, **kwargs):
+ for key in required:
+ if key not in args[0]:
+ raise KeyError('{0} not passed to {1}'.format(
+ key, function.__name__))
-def print_checkers(checkers):
- """ Print verbose checker help to stdout. """
+ return function(*args, **kwargs)
- print('')
- print('available checkers:')
- print('')
- for name in sorted(checkers.keys()):
- description, active = checkers[name]
- prefix = '+' if active else ' '
- if len(name) > 30:
- print(' {0} {1}'.format(prefix, name))
- print(' ' * 35 + description)
+ return wrapper
+
+ return decorator
+
+
+@require(['command', # entry from compilation database
+ 'directory', # entry from compilation database
+ 'file', # entry from compilation database
+ 'clang', # clang executable name (and path)
+ 'direct_args', # arguments from command line
+ 'force_debug', # kill non debug macros
+ 'output_dir', # where generated report files shall go
+ 'output_format', # it's 'plist' or 'html' or both
+ 'output_failures']) # generate crash reports or not
+def run(opts):
+ """ Entry point to run (or not) static analyzer against a single entry
+ of the compilation database.
+
+ This complex task is decomposed into smaller methods which are calling
+ each other in chain. If the analyzis is not possibe the given method
+ just return and break the chain.
+
+ The passed parameter is a python dictionary. Each method first check
+ that the needed parameters received. (This is done by the 'require'
+ decorator. It's like an 'assert' to check the contract between the
+ caller and the called method.) """
+
+ try:
+ command = opts.pop('command')
+ command = command if isinstance(command, list) else decode(command)
+ logging.debug("Run analyzer against '%s'", command)
+ opts.update(classify_parameters(command))
+
+ return arch_check(opts)
+ except Exception:
+ logging.error("Problem occured during analyzis.", exc_info=1)
+ return None
+
+
+@require(['clang', 'directory', 'flags', 'file', 'output_dir', 'language',
+ 'error_output', 'exit_code'])
+def report_failure(opts):
+ """ Create report when analyzer failed.
+
+ The major report is the preprocessor output. The output filename generated
+ randomly. The compiler output also captured into '.stderr.txt' file.
+ And some more execution context also saved into '.info.txt' file. """
+
+ def extension():
+ """ Generate preprocessor file extension. """
+
+ mapping = {'objective-c++': '.mii', 'objective-c': '.mi', 'c++': '.ii'}
+ return mapping.get(opts['language'], '.i')
+
+ def destination():
+ """ Creates failures directory if not exits yet. """
+
+ failures_dir = os.path.join(opts['output_dir'], 'failures')
+ if not os.path.isdir(failures_dir):
+ os.makedirs(failures_dir)
+ return failures_dir
+
+ # Classify error type: when Clang terminated by a signal it's a 'Crash'.
+ # (python subprocess Popen.returncode is negative when child terminated
+ # by signal.) Everything else is 'Other Error'.
+ error = 'crash' if opts['exit_code'] < 0 else 'other_error'
+ # Create preprocessor output file name. (This is blindly following the
+ # Perl implementation.)
+ (handle, name) = tempfile.mkstemp(suffix=extension(),
+ prefix='clang_' + error + '_',
+ dir=destination())
+ os.close(handle)
+ # Execute Clang again, but run the syntax check only.
+ cwd = opts['directory']
+ cmd = get_arguments(
+ [opts['clang'], '-fsyntax-only', '-E'
+ ] + opts['flags'] + [opts['file'], '-o', name], cwd)
+ run_command(cmd, cwd=cwd)
+ # write general information about the crash
+ with open(name + '.info.txt', 'w') as handle:
+ handle.write(opts['file'] + os.linesep)
+ handle.write(error.title().replace('_', ' ') + os.linesep)
+ handle.write(' '.join(cmd) + os.linesep)
+ handle.write(' '.join(os.uname()) + os.linesep)
+ handle.write(get_version(opts['clang']))
+ handle.close()
+ # write the captured output too
+ with open(name + '.stderr.txt', 'w') as handle:
+ handle.writelines(opts['error_output'])
+ handle.close()
+
+
+@require(['clang', 'directory', 'flags', 'direct_args', 'file', 'output_dir',
+ 'output_format'])
+def run_analyzer(opts, continuation=report_failure):
+ """ It assembles the analysis command line and executes it. Capture the
+ output of the analysis and returns with it. If failure reports are
+ requested, it calls the continuation to generate it. """
+
+ def target():
+ """ Creates output file name for reports. """
+ if opts['output_format'] in {'plist', 'plist-html'}:
+ (handle, name) = tempfile.mkstemp(prefix='report-',
+ suffix='.plist',
+ dir=opts['output_dir'])
+ os.close(handle)
+ return name
+ return opts['output_dir']
+
+ try:
+ cwd = opts['directory']
+ cmd = get_arguments([opts['clang'], '--analyze'] +
+ opts['direct_args'] + opts['flags'] +
+ [opts['file'], '-o', target()],
+ cwd)
+ output = run_command(cmd, cwd=cwd)
+ return {'error_output': output, 'exit_code': 0}
+ except subprocess.CalledProcessError as ex:
+ result = {'error_output': ex.output, 'exit_code': ex.returncode}
+ if opts.get('output_failures', False):
+ opts.update(result)
+ continuation(opts)
+ return result
+
+
+@require(['flags', 'force_debug'])
+def filter_debug_flags(opts, continuation=run_analyzer):
+ """ Filter out nondebug macros when requested. """
+
+ if opts.pop('force_debug'):
+ # lazy implementation just append an undefine macro at the end
+ opts.update({'flags': opts['flags'] + ['-UNDEBUG']})
+
+ return continuation(opts)
+
+
+@require(['language', 'compiler', 'file', 'flags'])
+def language_check(opts, continuation=filter_debug_flags):
+ """ Find out the language from command line parameters or file name
+ extension. The decision also influenced by the compiler invocation. """
+
+ accepted = frozenset({
+ 'c', 'c++', 'objective-c', 'objective-c++', 'c-cpp-output',
+ 'c++-cpp-output', 'objective-c-cpp-output'
+ })
+
+ # language can be given as a parameter...
+ language = opts.pop('language')
+ compiler = opts.pop('compiler')
+ # ... or find out from source file extension
+ if language is None and compiler is not None:
+ language = classify_source(opts['file'], compiler == 'c')
+
+ if language is None:
+ logging.debug('skip analysis, language not known')
+ return None
+ elif language not in accepted:
+ logging.debug('skip analysis, language not supported')
+ return None
+ else:
+ logging.debug('analysis, language: %s', language)
+ opts.update({'language': language,
+ 'flags': ['-x', language] + opts['flags']})
+ return continuation(opts)
+
+
+@require(['arch_list', 'flags'])
+def arch_check(opts, continuation=language_check):
+ """ Do run analyzer through one of the given architectures. """
+
+ disabled = frozenset({'ppc', 'ppc64'})
+
+ received_list = opts.pop('arch_list')
+ if received_list:
+ # filter out disabled architectures and -arch switches
+ filtered_list = [a for a in received_list if a not in disabled]
+ if filtered_list:
+ # There should be only one arch given (or the same multiple
+ # times). If there are multiple arch are given and are not
+ # the same, those should not change the pre-processing step.
+ # But that's the only pass we have before run the analyzer.
+ current = filtered_list.pop()
+ logging.debug('analysis, on arch: %s', current)
+
+ opts.update({'flags': ['-arch', current] + opts['flags']})
+ return continuation(opts)
else:
- print(' {0} {1: <30} {2}'.format(prefix, name, description))
- print('')
- print('NOTE: "+" indicates that an analysis is enabled by default.')
- print('')
-
-
-def validate(parser, args, from_build_command):
- """ Validation done by the parser itself, but semantic check still
- needs to be done. This method is doing that. """
-
- # Make plugins always a list. (It might be None when not specified.)
- args.plugins = args.plugins if args.plugins else []
-
- if args.help_checkers_verbose:
- print_checkers(get_checkers(args.clang, args.plugins))
- parser.exit()
- elif args.help_checkers:
- print_active_checkers(get_checkers(args.clang, args.plugins))
- parser.exit()
-
- if from_build_command and not args.build:
- parser.error('missing build command')
-
-
-def create_parser(from_build_command):
- """ Command line argument parser factory method. """
-
- parser = argparse.ArgumentParser(
- formatter_class=argparse.ArgumentDefaultsHelpFormatter)
-
- parser.add_argument(
- '--verbose', '-v',
- action='count',
- default=0,
- help="""Enable verbose output from '%(prog)s'. A second and third
- flag increases verbosity.""")
- parser.add_argument(
- '--override-compiler',
- action='store_true',
- help="""Always resort to the compiler wrapper even when better
- interposition methods are available.""")
- parser.add_argument(
- '--intercept-first',
- action='store_true',
- help="""Run the build commands only, build a compilation database,
- then run the static analyzer afterwards.
- Generally speaking it has better coverage on build commands.
- With '--override-compiler' it use compiler wrapper, but does
- not run the analyzer till the build is finished. """)
- parser.add_argument(
- '--cdb',
- metavar='<file>',
- default="compile_commands.json",
- help="""The JSON compilation database.""")
-
- parser.add_argument(
- '--output', '-o',
- metavar='<path>',
- default=tempdir(),
- help="""Specifies the output directory for analyzer reports.
- Subdirectory will be created if default directory is targeted.
- """)
- parser.add_argument(
- '--status-bugs',
- action='store_true',
- help="""By default, the exit status of '%(prog)s' is the same as the
- executed build command. Specifying this option causes the exit
- status of '%(prog)s' to be non zero if it found potential bugs
- and zero otherwise.""")
- parser.add_argument(
- '--html-title',
- metavar='<title>',
- help="""Specify the title used on generated HTML pages.
- If not specified, a default title will be used.""")
- parser.add_argument(
- '--analyze-headers',
- action='store_true',
- help="""Also analyze functions in #included files. By default, such
- functions are skipped unless they are called by functions
- within the main source file.""")
- format_group = parser.add_mutually_exclusive_group()
- format_group.add_argument(
- '--plist', '-plist',
- dest='output_format',
- const='plist',
- default='html',
- action='store_const',
- help="""This option outputs the results as a set of .plist files.""")
- format_group.add_argument(
- '--plist-html', '-plist-html',
- dest='output_format',
- const='plist-html',
- default='html',
- action='store_const',
- help="""This option outputs the results as a set of .html and .plist
- files.""")
- # TODO: implement '-view '
-
- advanced = parser.add_argument_group('advanced options')
- advanced.add_argument(
- '--keep-empty',
- action='store_true',
- help="""Don't remove the build results directory even if no issues
- were reported.""")
- advanced.add_argument(
- '--no-failure-reports', '-no-failure-reports',
- dest='output_failures',
- action='store_false',
- help="""Do not create a 'failures' subdirectory that includes analyzer
- crash reports and preprocessed source files.""")
- advanced.add_argument(
- '--stats', '-stats',
- action='store_true',
- help="""Generates visitation statistics for the project being analyzed.
- """)
- advanced.add_argument(
- '--internal-stats',
- action='store_true',
- help="""Generate internal analyzer statistics.""")
- advanced.add_argument(
- '--maxloop', '-maxloop',
- metavar='<loop count>',
- type=int,
- help="""Specifiy the number of times a block can be visited before
- giving up. Increase for more comprehensive coverage at a cost
- of speed.""")
- advanced.add_argument(
- '--store', '-store',
- metavar='<model>',
- dest='store_model',
- choices=['region', 'basic'],
- help="""Specify the store model used by the analyzer.
- 'region' specifies a field- sensitive store model.
- 'basic' which is far less precise but can more quickly
- analyze code. 'basic' was the default store model for
- checker-0.221 and earlier.""")
- advanced.add_argument(
- '--constraints', '-constraints',
- metavar='<model>',
- dest='constraints_model',
- choices=['range', 'basic'],
- help="""Specify the contraint engine used by the analyzer. Specifying
- 'basic' uses a simpler, less powerful constraint model used by
- checker-0.160 and earlier.""")
- advanced.add_argument(
- '--use-analyzer',
- metavar='<path>',
- dest='clang',
- default='clang',
- help="""'%(prog)s' uses the 'clang' executable relative to itself for
- static analysis. One can override this behavior with this
- option by using the 'clang' packaged with Xcode (on OS X) or
- from the PATH.""")
- advanced.add_argument(
- '--use-cc',
- metavar='<path>',
- dest='cc',
- default='cc',
- help="""When '%(prog)s' analyzes a project by interposing a "fake
- compiler", which executes a real compiler for compilation and
- do other tasks (to run the static analyzer or just record the
- compiler invocation). Because of this interposing, '%(prog)s'
- does not know what compiler your project normally uses.
- Instead, it simply overrides the CC environment variable, and
- guesses your default compiler.
-
- If you need '%(prog)s' to use a specific compiler for
- *compilation* then you can use this option to specify a path
- to that compiler.""")
- advanced.add_argument(
- '--use-c++',
- metavar='<path>',
- dest='cxx',
- default='c++',
- help="""This is the same as "--use-cc" but for C++ code.""")
- advanced.add_argument(
- '--analyzer-config', '-analyzer-config',
- metavar='<options>',
- help="""Provide options to pass through to the analyzer's
- -analyzer-config flag. Several options are separated with
- comma: 'key1=val1,key2=val2'
-
- Available options:
- stable-report-filename=true or false (default)
-
- Switch the page naming to:
- report-<filename>-<function/method name>-<id>.html
- instead of report-XXXXXX.html""")
- advanced.add_argument(
- '--exclude',
- metavar='<directory>',
- dest='excludes',
- action='append',
- default=[],
- help="""Do not run static analyzer against files found in this
- directory. (You can specify this option multiple times.)
- Could be usefull when project contains 3rd party libraries.
- The directory path shall be absolute path as file names in
- the compilation database.""")
- advanced.add_argument(
- '--force-analyze-debug-code',
- dest='force_debug',
- action='store_true',
- help="""Tells analyzer to enable assertions in code even if they were
- disabled during compilation, enabling more precise results.""")
-
- plugins = parser.add_argument_group('checker options')
- plugins.add_argument(
- '--load-plugin', '-load-plugin',
- metavar='<plugin library>',
- dest='plugins',
- action='append',
- help="""Loading external checkers using the clang plugin interface.""")
- plugins.add_argument(
- '--enable-checker', '-enable-checker',
- metavar='<checker name>',
- action=AppendCommaSeparated,
- help="""Enable specific checker.""")
- plugins.add_argument(
- '--disable-checker', '-disable-checker',
- metavar='<checker name>',
- action=AppendCommaSeparated,
- help="""Disable specific checker.""")
- plugins.add_argument(
- '--help-checkers',
- action='store_true',
- help="""A default group of checkers is run unless explicitly disabled.
- Exactly which checkers constitute the default group is a
- function of the operating system in use. These can be printed
- with this flag.""")
- plugins.add_argument(
- '--help-checkers-verbose',
- action='store_true',
- help="""Print all available checkers and mark the enabled ones.""")
-
- if from_build_command:
- parser.add_argument(
- dest='build',
- nargs=argparse.REMAINDER,
- help="""Command to run.""")
-
- return parser
-
-
-class AppendCommaSeparated(argparse.Action):
- """ argparse Action class to support multiple comma separated lists. """
-
- def __call__(self, __parser, namespace, values, __option_string):
- # getattr(obj, attr, default) does not really returns default but none
- if getattr(namespace, self.dest, None) is None:
- setattr(namespace, self.dest, [])
- # once it's fixed we can use as expected
- actual = getattr(namespace, self.dest)
- actual.extend(values.split(','))
- setattr(namespace, self.dest, actual)
+ logging.debug('skip analysis, found not supported arch')
+ return None
+ else:
+ logging.debug('analysis, on default arch')
+ return continuation(opts)
+
+# To have good results from static analyzer certain compiler options shall be
+# omitted. The compiler flag filtering only affects the static analyzer run.
+#
+# Keys are the option name, value number of options to skip
+IGNORED_FLAGS = {
+ '-c': 0, # compile option will be overwritten
+ '-fsyntax-only': 0, # static analyzer option will be overwritten
+ '-o': 1, # will set up own output file
+ # flags below are inherited from the perl implementation.
+ '-g': 0,
+ '-save-temps': 0,
+ '-install_name': 1,
+ '-exported_symbols_list': 1,
+ '-current_version': 1,
+ '-compatibility_version': 1,
+ '-init': 1,
+ '-e': 1,
+ '-seg1addr': 1,
+ '-bundle_loader': 1,
+ '-multiply_defined': 1,
+ '-sectorder': 3,
+ '--param': 1,
+ '--serialize-diagnostics': 1
+}
+
+
+def classify_parameters(command):
+ """ Prepare compiler flags (filters some and add others) and take out
+ language (-x) and architecture (-arch) flags for future processing. """
+
+ result = {
+ 'flags': [], # the filtered compiler flags
+ 'arch_list': [], # list of architecture flags
+ 'language': None, # compilation language, None, if not specified
+ 'compiler': compiler_language(command) # 'c' or 'c++'
+ }
+
+ # iterate on the compile options
+ args = iter(command[1:])
+ for arg in args:
+ # take arch flags into a separate basket
+ if arg == '-arch':
+ result['arch_list'].append(next(args))
+ # take language
+ elif arg == '-x':
+ result['language'] = next(args)
+ # parameters which looks source file are not flags
+ elif re.match(r'^[^-].+', arg) and classify_source(arg):
+ pass
+ # ignore some flags
+ elif arg in IGNORED_FLAGS:
+ count = IGNORED_FLAGS[arg]
+ for _ in range(count):
+ next(args)
+ # we don't care about extra warnings, but we should suppress ones
+ # that we don't want to see.
+ elif re.match(r'^-W.+', arg) and not re.match(r'^-Wno-.+', arg):
+ pass
+ # and consider everything else as compilation flag.
+ else:
+ result['flags'].append(arg)
+
+ return result
diff --git a/tools/scan-build-py/libscanbuild/arguments.py b/tools/scan-build-py/libscanbuild/arguments.py
new file mode 100644
index 000000000000..2735123f9f16
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/arguments.py
@@ -0,0 +1,431 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module parses and validates arguments for command-line interfaces.
+
+It uses argparse module to create the command line parser. (This library is
+in the standard python library since 3.2 and backported to 2.7, but not
+earlier.)
+
+It also implements basic validation methods, related to the command.
+Validations are mostly calling specific help methods, or mangling values.
+"""
+
+import os
+import sys
+import argparse
+import logging
+import tempfile
+from libscanbuild import reconfigure_logging
+from libscanbuild.clang import get_checkers
+
+__all__ = ['parse_args_for_intercept_build', 'parse_args_for_analyze_build',
+ 'parse_args_for_scan_build']
+
+
+def parse_args_for_intercept_build():
+ """ Parse and validate command-line arguments for intercept-build. """
+
+ parser = create_intercept_parser()
+ args = parser.parse_args()
+
+ reconfigure_logging(args.verbose)
+ logging.debug('Raw arguments %s', sys.argv)
+
+ # short validation logic
+ if not args.build:
+ parser.error(message='missing build command')
+
+ logging.debug('Parsed arguments: %s', args)
+ return args
+
+
+def parse_args_for_analyze_build():
+ """ Parse and validate command-line arguments for analyze-build. """
+
+ from_build_command = False
+ parser = create_analyze_parser(from_build_command)
+ args = parser.parse_args()
+
+ reconfigure_logging(args.verbose)
+ logging.debug('Raw arguments %s', sys.argv)
+
+ normalize_args_for_analyze(args, from_build_command)
+ validate_args_for_analyze(parser, args, from_build_command)
+ logging.debug('Parsed arguments: %s', args)
+ return args
+
+
+def parse_args_for_scan_build():
+ """ Parse and validate command-line arguments for scan-build. """
+
+ from_build_command = True
+ parser = create_analyze_parser(from_build_command)
+ args = parser.parse_args()
+
+ reconfigure_logging(args.verbose)
+ logging.debug('Raw arguments %s', sys.argv)
+
+ normalize_args_for_analyze(args, from_build_command)
+ validate_args_for_analyze(parser, args, from_build_command)
+ logging.debug('Parsed arguments: %s', args)
+ return args
+
+
+def normalize_args_for_analyze(args, from_build_command):
+ """ Normalize parsed arguments for analyze-build and scan-build.
+
+ :param args: Parsed argument object. (Will be mutated.)
+ :param from_build_command: Boolean value tells is the command suppose
+ to run the analyzer against a build command or a compilation db. """
+
+ # make plugins always a list. (it might be None when not specified.)
+ if args.plugins is None:
+ args.plugins = []
+
+ # make exclude directory list unique and absolute.
+ uniq_excludes = set(os.path.abspath(entry) for entry in args.excludes)
+ args.excludes = list(uniq_excludes)
+
+ # because shared codes for all tools, some common used methods are
+ # expecting some argument to be present. so, instead of query the args
+ # object about the presence of the flag, we fake it here. to make those
+ # methods more readable. (it's an arguable choice, took it only for those
+ # which have good default value.)
+ if from_build_command:
+ # add cdb parameter invisibly to make report module working.
+ args.cdb = 'compile_commands.json'
+
+
+def validate_args_for_analyze(parser, args, from_build_command):
+ """ Command line parsing is done by the argparse module, but semantic
+ validation still needs to be done. This method is doing it for
+ analyze-build and scan-build commands.
+
+ :param parser: The command line parser object.
+ :param args: Parsed argument object.
+ :param from_build_command: Boolean value tells is the command suppose
+ to run the analyzer against a build command or a compilation db.
+ :return: No return value, but this call might throw when validation
+ fails. """
+
+ if args.help_checkers_verbose:
+ print_checkers(get_checkers(args.clang, args.plugins))
+ parser.exit(status=0)
+ elif args.help_checkers:
+ print_active_checkers(get_checkers(args.clang, args.plugins))
+ parser.exit(status=0)
+ elif from_build_command and not args.build:
+ parser.error(message='missing build command')
+ elif not from_build_command and not os.path.exists(args.cdb):
+ parser.error(message='compilation database is missing')
+
+
+def create_intercept_parser():
+ """ Creates a parser for command-line arguments to 'intercept'. """
+
+ parser = create_default_parser()
+ parser_add_cdb(parser)
+
+ parser_add_prefer_wrapper(parser)
+ parser_add_compilers(parser)
+
+ advanced = parser.add_argument_group('advanced options')
+ group = advanced.add_mutually_exclusive_group()
+ group.add_argument(
+ '--append',
+ action='store_true',
+ help="""Extend existing compilation database with new entries.
+ Duplicate entries are detected and not present in the final output.
+ The output is not continuously updated, it's done when the build
+ command finished. """)
+
+ parser.add_argument(
+ dest='build', nargs=argparse.REMAINDER, help="""Command to run.""")
+ return parser
+
+
+def create_analyze_parser(from_build_command):
+ """ Creates a parser for command-line arguments to 'analyze'. """
+
+ parser = create_default_parser()
+
+ if from_build_command:
+ parser_add_prefer_wrapper(parser)
+ parser_add_compilers(parser)
+
+ parser.add_argument(
+ '--intercept-first',
+ action='store_true',
+ help="""Run the build commands first, intercept compiler
+ calls and then run the static analyzer afterwards.
+ Generally speaking it has better coverage on build commands.
+ With '--override-compiler' it use compiler wrapper, but does
+ not run the analyzer till the build is finished.""")
+ else:
+ parser_add_cdb(parser)
+
+ parser.add_argument(
+ '--status-bugs',
+ action='store_true',
+ help="""The exit status of '%(prog)s' is the same as the executed
+ build command. This option ignores the build exit status and sets to
+ be non zero if it found potential bugs or zero otherwise.""")
+ parser.add_argument(
+ '--exclude',
+ metavar='<directory>',
+ dest='excludes',
+ action='append',
+ default=[],
+ help="""Do not run static analyzer against files found in this
+ directory. (You can specify this option multiple times.)
+ Could be useful when project contains 3rd party libraries.""")
+
+ output = parser.add_argument_group('output control options')
+ output.add_argument(
+ '--output',
+ '-o',
+ metavar='<path>',
+ default=tempfile.gettempdir(),
+ help="""Specifies the output directory for analyzer reports.
+ Subdirectory will be created if default directory is targeted.""")
+ output.add_argument(
+ '--keep-empty',
+ action='store_true',
+ help="""Don't remove the build results directory even if no issues
+ were reported.""")
+ output.add_argument(
+ '--html-title',
+ metavar='<title>',
+ help="""Specify the title used on generated HTML pages.
+ If not specified, a default title will be used.""")
+ format_group = output.add_mutually_exclusive_group()
+ format_group.add_argument(
+ '--plist',
+ '-plist',
+ dest='output_format',
+ const='plist',
+ default='html',
+ action='store_const',
+ help="""Cause the results as a set of .plist files.""")
+ format_group.add_argument(
+ '--plist-html',
+ '-plist-html',
+ dest='output_format',
+ const='plist-html',
+ default='html',
+ action='store_const',
+ help="""Cause the results as a set of .html and .plist files.""")
+ # TODO: implement '-view '
+
+ advanced = parser.add_argument_group('advanced options')
+ advanced.add_argument(
+ '--use-analyzer',
+ metavar='<path>',
+ dest='clang',
+ default='clang',
+ help="""'%(prog)s' uses the 'clang' executable relative to itself for
+ static analysis. One can override this behavior with this option by
+ using the 'clang' packaged with Xcode (on OS X) or from the PATH.""")
+ advanced.add_argument(
+ '--no-failure-reports',
+ '-no-failure-reports',
+ dest='output_failures',
+ action='store_false',
+ help="""Do not create a 'failures' subdirectory that includes analyzer
+ crash reports and preprocessed source files.""")
+ parser.add_argument(
+ '--analyze-headers',
+ action='store_true',
+ help="""Also analyze functions in #included files. By default, such
+ functions are skipped unless they are called by functions within the
+ main source file.""")
+ advanced.add_argument(
+ '--stats',
+ '-stats',
+ action='store_true',
+ help="""Generates visitation statistics for the project.""")
+ advanced.add_argument(
+ '--internal-stats',
+ action='store_true',
+ help="""Generate internal analyzer statistics.""")
+ advanced.add_argument(
+ '--maxloop',
+ '-maxloop',
+ metavar='<loop count>',
+ type=int,
+ help="""Specifiy the number of times a block can be visited before
+ giving up. Increase for more comprehensive coverage at a cost of
+ speed.""")
+ advanced.add_argument(
+ '--store',
+ '-store',
+ metavar='<model>',
+ dest='store_model',
+ choices=['region', 'basic'],
+ help="""Specify the store model used by the analyzer. 'region'
+ specifies a field- sensitive store model. 'basic' which is far less
+ precise but can more quickly analyze code. 'basic' was the default
+ store model for checker-0.221 and earlier.""")
+ advanced.add_argument(
+ '--constraints',
+ '-constraints',
+ metavar='<model>',
+ dest='constraints_model',
+ choices=['range', 'basic'],
+ help="""Specify the constraint engine used by the analyzer. Specifying
+ 'basic' uses a simpler, less powerful constraint model used by
+ checker-0.160 and earlier.""")
+ advanced.add_argument(
+ '--analyzer-config',
+ '-analyzer-config',
+ metavar='<options>',
+ help="""Provide options to pass through to the analyzer's
+ -analyzer-config flag. Several options are separated with comma:
+ 'key1=val1,key2=val2'
+
+ Available options:
+ stable-report-filename=true or false (default)
+
+ Switch the page naming to:
+ report-<filename>-<function/method name>-<id>.html
+ instead of report-XXXXXX.html""")
+ advanced.add_argument(
+ '--force-analyze-debug-code',
+ dest='force_debug',
+ action='store_true',
+ help="""Tells analyzer to enable assertions in code even if they were
+ disabled during compilation, enabling more precise results.""")
+
+ plugins = parser.add_argument_group('checker options')
+ plugins.add_argument(
+ '--load-plugin',
+ '-load-plugin',
+ metavar='<plugin library>',
+ dest='plugins',
+ action='append',
+ help="""Loading external checkers using the clang plugin interface.""")
+ plugins.add_argument(
+ '--enable-checker',
+ '-enable-checker',
+ metavar='<checker name>',
+ action=AppendCommaSeparated,
+ help="""Enable specific checker.""")
+ plugins.add_argument(
+ '--disable-checker',
+ '-disable-checker',
+ metavar='<checker name>',
+ action=AppendCommaSeparated,
+ help="""Disable specific checker.""")
+ plugins.add_argument(
+ '--help-checkers',
+ action='store_true',
+ help="""A default group of checkers is run unless explicitly disabled.
+ Exactly which checkers constitute the default group is a function of
+ the operating system in use. These can be printed with this flag.""")
+ plugins.add_argument(
+ '--help-checkers-verbose',
+ action='store_true',
+ help="""Print all available checkers and mark the enabled ones.""")
+
+ if from_build_command:
+ parser.add_argument(
+ dest='build', nargs=argparse.REMAINDER, help="""Command to run.""")
+ return parser
+
+
+def create_default_parser():
+ """ Creates command line parser for all build wrapper commands. """
+
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+ parser.add_argument(
+ '--verbose',
+ '-v',
+ action='count',
+ default=0,
+ help="""Enable verbose output from '%(prog)s'. A second, third and
+ fourth flags increases verbosity.""")
+ return parser
+
+
+def parser_add_cdb(parser):
+ parser.add_argument(
+ '--cdb',
+ metavar='<file>',
+ default="compile_commands.json",
+ help="""The JSON compilation database.""")
+
+
+def parser_add_prefer_wrapper(parser):
+ parser.add_argument(
+ '--override-compiler',
+ action='store_true',
+ help="""Always resort to the compiler wrapper even when better
+ intercept methods are available.""")
+
+
+def parser_add_compilers(parser):
+ parser.add_argument(
+ '--use-cc',
+ metavar='<path>',
+ dest='cc',
+ default=os.getenv('CC', 'cc'),
+ help="""When '%(prog)s' analyzes a project by interposing a compiler
+ wrapper, which executes a real compiler for compilation and do other
+ tasks (record the compiler invocation). Because of this interposing,
+ '%(prog)s' does not know what compiler your project normally uses.
+ Instead, it simply overrides the CC environment variable, and guesses
+ your default compiler.
+
+ If you need '%(prog)s' to use a specific compiler for *compilation*
+ then you can use this option to specify a path to that compiler.""")
+ parser.add_argument(
+ '--use-c++',
+ metavar='<path>',
+ dest='cxx',
+ default=os.getenv('CXX', 'c++'),
+ help="""This is the same as "--use-cc" but for C++ code.""")
+
+
+class AppendCommaSeparated(argparse.Action):
+ """ argparse Action class to support multiple comma separated lists. """
+
+ def __call__(self, __parser, namespace, values, __option_string):
+ # getattr(obj, attr, default) does not really returns default but none
+ if getattr(namespace, self.dest, None) is None:
+ setattr(namespace, self.dest, [])
+ # once it's fixed we can use as expected
+ actual = getattr(namespace, self.dest)
+ actual.extend(values.split(','))
+ setattr(namespace, self.dest, actual)
+
+
+def print_active_checkers(checkers):
+ """ Print active checkers to stdout. """
+
+ for name in sorted(name for name, (_, active) in checkers.items()
+ if active):
+ print(name)
+
+
+def print_checkers(checkers):
+ """ Print verbose checker help to stdout. """
+
+ print('')
+ print('available checkers:')
+ print('')
+ for name in sorted(checkers.keys()):
+ description, active = checkers[name]
+ prefix = '+' if active else ' '
+ if len(name) > 30:
+ print(' {0} {1}'.format(prefix, name))
+ print(' ' * 35 + description)
+ else:
+ print(' {0} {1: <30} {2}'.format(prefix, name, description))
+ print('')
+ print('NOTE: "+" indicates that an analysis is enabled by default.')
+ print('')
diff --git a/tools/scan-build-py/libscanbuild/clang.py b/tools/scan-build-py/libscanbuild/clang.py
index 833e77d28bbe..192e708782c1 100644
--- a/tools/scan-build-py/libscanbuild/clang.py
+++ b/tools/scan-build-py/libscanbuild/clang.py
@@ -9,8 +9,7 @@ Since Clang command line interface is so rich, but this project is using only
a subset of that, it makes sense to create a function specific wrapper. """
import re
-import subprocess
-import logging
+from libscanbuild import run_command
from libscanbuild.shell import decode
__all__ = ['get_version', 'get_arguments', 'get_checkers']
@@ -25,8 +24,9 @@ def get_version(clang):
:param clang: the compiler we are using
:return: the version string printed to stderr """
- output = subprocess.check_output([clang, '-v'], stderr=subprocess.STDOUT)
- return output.decode('utf-8').splitlines()[0]
+ output = run_command([clang, '-v'])
+ # the relevant version info is in the first line
+ return output[0]
def get_arguments(command, cwd):
@@ -38,12 +38,11 @@ def get_arguments(command, cwd):
cmd = command[:]
cmd.insert(1, '-###')
- logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
- output = subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT)
+ output = run_command(cmd, cwd=cwd)
# The relevant information is in the last line of the output.
# Don't check if finding last line fails, would throw exception anyway.
- last_line = output.decode('utf-8').splitlines()[-1]
+ last_line = output[-1]
if re.search(r'clang(.*): error:', last_line):
raise Exception(last_line)
return decode(last_line)
@@ -141,9 +140,7 @@ def get_checkers(clang, plugins):
load = [elem for plugin in plugins for elem in ['-load', plugin]]
cmd = [clang, '-cc1'] + load + ['-analyzer-checker-help']
- logging.debug('exec command: %s', ' '.join(cmd))
- output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
- lines = output.decode('utf-8').splitlines()
+ lines = run_command(cmd)
is_active_checker = is_active(get_active_checkers(clang, plugins))
diff --git a/tools/scan-build-py/libscanbuild/intercept.py b/tools/scan-build-py/libscanbuild/intercept.py
index 6a9f75349fb5..b9bf9e917526 100644
--- a/tools/scan-build-py/libscanbuild/intercept.py
+++ b/tools/scan-build-py/libscanbuild/intercept.py
@@ -27,16 +27,16 @@ import re
import itertools
import json
import glob
-import argparse
import logging
-import subprocess
from libear import build_libear, TemporaryDirectory
-from libscanbuild import command_entry_point
-from libscanbuild import duplicate_check, tempdir, initialize_logging
+from libscanbuild import command_entry_point, compiler_wrapper, \
+ wrapper_environment, run_command, run_build
+from libscanbuild import duplicate_check
from libscanbuild.compilation import split_command
+from libscanbuild.arguments import parse_args_for_intercept_build
from libscanbuild.shell import encode, decode
-__all__ = ['capture', 'intercept_build_main', 'intercept_build_wrapper']
+__all__ = ['capture', 'intercept_build', 'intercept_compiler_wrapper']
GS = chr(0x1d)
RS = chr(0x1e)
@@ -44,26 +44,19 @@ US = chr(0x1f)
COMPILER_WRAPPER_CC = 'intercept-cc'
COMPILER_WRAPPER_CXX = 'intercept-c++'
+TRACE_FILE_EXTENSION = '.cmd' # same as in ear.c
+WRAPPER_ONLY_PLATFORMS = frozenset({'win32', 'cygwin'})
@command_entry_point
-def intercept_build_main(bin_dir):
+def intercept_build():
""" Entry point for 'intercept-build' command. """
- parser = create_parser()
- args = parser.parse_args()
+ args = parse_args_for_intercept_build()
+ return capture(args)
- initialize_logging(args.verbose)
- logging.debug('Parsed arguments: %s', args)
- if not args.build:
- parser.print_help()
- return 0
-
- return capture(args, bin_dir)
-
-
-def capture(args, bin_dir):
+def capture(args):
""" The entry point of build command interception. """
def post_processing(commands):
@@ -91,28 +84,23 @@ def capture(args, bin_dir):
for entry in itertools.chain(previous, current)
if os.path.exists(entry['file']) and not duplicate(entry))
- with TemporaryDirectory(prefix='intercept-', dir=tempdir()) as tmp_dir:
+ with TemporaryDirectory(prefix='intercept-') as tmp_dir:
# run the build command
- environment = setup_environment(args, tmp_dir, bin_dir)
- logging.debug('run build in environment: %s', environment)
- exit_code = subprocess.call(args.build, env=environment)
- logging.info('build finished with exit code: %d', exit_code)
+ environment = setup_environment(args, tmp_dir)
+ exit_code = run_build(args.build, env=environment)
# read the intercepted exec calls
exec_traces = itertools.chain.from_iterable(
parse_exec_trace(os.path.join(tmp_dir, filename))
for filename in sorted(glob.iglob(os.path.join(tmp_dir, '*.cmd'))))
- # do post processing only if that was requested
- if 'raw_entries' not in args or not args.raw_entries:
- entries = post_processing(exec_traces)
- else:
- entries = exec_traces
+ # do post processing
+ entries = post_processing(exec_traces)
# dump the compilation database
with open(args.cdb, 'w+') as handle:
json.dump(list(entries), handle, sort_keys=True, indent=4)
return exit_code
-def setup_environment(args, destination, bin_dir):
+def setup_environment(args, destination):
""" Sets up the environment for the build command.
It sets the required environment variables and execute the given command.
@@ -130,12 +118,10 @@ def setup_environment(args, destination, bin_dir):
if not libear_path:
logging.debug('intercept gonna use compiler wrappers')
+ environment.update(wrapper_environment(args))
environment.update({
- 'CC': os.path.join(bin_dir, COMPILER_WRAPPER_CC),
- 'CXX': os.path.join(bin_dir, COMPILER_WRAPPER_CXX),
- 'INTERCEPT_BUILD_CC': c_compiler,
- 'INTERCEPT_BUILD_CXX': cxx_compiler,
- 'INTERCEPT_BUILD_VERBOSE': 'DEBUG' if args.verbose > 2 else 'INFO'
+ 'CC': COMPILER_WRAPPER_CC,
+ 'CXX': COMPILER_WRAPPER_CXX
})
elif sys.platform == 'darwin':
logging.debug('intercept gonna preload libear on OSX')
@@ -150,42 +136,49 @@ def setup_environment(args, destination, bin_dir):
return environment
-def intercept_build_wrapper(cplusplus):
- """ Entry point for `intercept-cc` and `intercept-c++` compiler wrappers.
+@command_entry_point
+def intercept_compiler_wrapper():
+ """ Entry point for `intercept-cc` and `intercept-c++`. """
+
+ return compiler_wrapper(intercept_compiler_wrapper_impl)
+
+
+def intercept_compiler_wrapper_impl(_, execution):
+ """ Implement intercept compiler wrapper functionality.
- It does generate execution report into target directory. And execute
- the wrapped compilation with the real compiler. The parameters for
- report and execution are from environment variables.
+ It does generate execution report into target directory.
+ The target directory name is from environment variables. """
- Those parameters which for 'libear' library can't have meaningful
- values are faked. """
+ message_prefix = 'execution report might be incomplete: %s'
- # initialize wrapper logging
- logging.basicConfig(format='intercept: %(levelname)s: %(message)s',
- level=os.getenv('INTERCEPT_BUILD_VERBOSE', 'INFO'))
- # write report
+ target_dir = os.getenv('INTERCEPT_BUILD_TARGET_DIR')
+ if not target_dir:
+ logging.warning(message_prefix, 'missing target directory')
+ return
+ # write current execution info to the pid file
try:
- target_dir = os.getenv('INTERCEPT_BUILD_TARGET_DIR')
- if not target_dir:
- raise UserWarning('exec report target directory not found')
- pid = str(os.getpid())
- target_file = os.path.join(target_dir, pid + '.cmd')
- logging.debug('writing exec report to: %s', target_file)
- with open(target_file, 'ab') as handler:
- working_dir = os.getcwd()
- command = US.join(sys.argv) + US
- content = RS.join([pid, pid, 'wrapper', working_dir, command]) + GS
- handler.write(content.encode('utf-8'))
+ target_file_name = str(os.getpid()) + TRACE_FILE_EXTENSION
+ target_file = os.path.join(target_dir, target_file_name)
+ logging.debug('writing execution report to: %s', target_file)
+ write_exec_trace(target_file, execution)
except IOError:
- logging.exception('writing exec report failed')
- except UserWarning as warning:
- logging.warning(warning)
- # execute with real compiler
- compiler = os.getenv('INTERCEPT_BUILD_CXX', 'c++') if cplusplus \
- else os.getenv('INTERCEPT_BUILD_CC', 'cc')
- compilation = [compiler] + sys.argv[1:]
- logging.debug('execute compiler: %s', compilation)
- return subprocess.call(compilation)
+ logging.warning(message_prefix, 'io problem')
+
+
+def write_exec_trace(filename, entry):
+ """ Write execution report file.
+
+ This method shall be sync with the execution report writer in interception
+ library. The entry in the file is a JSON objects.
+
+ :param filename: path to the output execution trace file,
+ :param entry: the Execution object to append to that file. """
+
+ with open(filename, 'ab') as handler:
+ pid = str(entry.pid)
+ command = US.join(entry.cmd) + US
+ content = RS.join([pid, pid, 'wrapper', entry.cwd, command]) + GS
+ handler.write(content.encode('utf-8'))
def parse_exec_trace(filename):
@@ -238,24 +231,21 @@ def is_preload_disabled(platform):
the path and, if so, (2) whether the output of executing 'csrutil status'
contains 'System Integrity Protection status: enabled'.
- Same problem on linux when SELinux is enabled. The status query program
- 'sestatus' and the output when it's enabled 'SELinux status: enabled'. """
+ :param platform: name of the platform (returned by sys.platform),
+ :return: True if library preload will fail by the dynamic linker. """
- if platform == 'darwin':
- pattern = re.compile(r'System Integrity Protection status:\s+enabled')
+ if platform in WRAPPER_ONLY_PLATFORMS:
+ return True
+ elif platform == 'darwin':
command = ['csrutil', 'status']
- elif platform in {'linux', 'linux2'}:
- pattern = re.compile(r'SELinux status:\s+enabled')
- command = ['sestatus']
+ pattern = re.compile(r'System Integrity Protection status:\s+enabled')
+ try:
+ return any(pattern.match(line) for line in run_command(command))
+ except:
+ return False
else:
return False
- try:
- lines = subprocess.check_output(command).decode('utf-8')
- return any((pattern.match(line) for line in lines.splitlines()))
- except:
- return False
-
def entry_hash(entry):
""" Implement unique hash method for compilation database entries. """
@@ -271,69 +261,3 @@ def entry_hash(entry):
command = ' '.join(decode(entry['command'])[1:])
return '<>'.join([filename, directory, command])
-
-
-def create_parser():
- """ Command line argument parser factory method. """
-
- parser = argparse.ArgumentParser(
- formatter_class=argparse.ArgumentDefaultsHelpFormatter)
-
- parser.add_argument(
- '--verbose', '-v',
- action='count',
- default=0,
- help="""Enable verbose output from '%(prog)s'. A second and third
- flag increases verbosity.""")
- parser.add_argument(
- '--cdb',
- metavar='<file>',
- default="compile_commands.json",
- help="""The JSON compilation database.""")
- group = parser.add_mutually_exclusive_group()
- group.add_argument(
- '--append',
- action='store_true',
- help="""Append new entries to existing compilation database.""")
- group.add_argument(
- '--disable-filter', '-n',
- dest='raw_entries',
- action='store_true',
- help="""Intercepted child process creation calls (exec calls) are all
- logged to the output. The output is not a compilation database.
- This flag is for debug purposes.""")
-
- advanced = parser.add_argument_group('advanced options')
- advanced.add_argument(
- '--override-compiler',
- action='store_true',
- help="""Always resort to the compiler wrapper even when better
- intercept methods are available.""")
- advanced.add_argument(
- '--use-cc',
- metavar='<path>',
- dest='cc',
- default='cc',
- help="""When '%(prog)s' analyzes a project by interposing a compiler
- wrapper, which executes a real compiler for compilation and
- do other tasks (record the compiler invocation). Because of
- this interposing, '%(prog)s' does not know what compiler your
- project normally uses. Instead, it simply overrides the CC
- environment variable, and guesses your default compiler.
-
- If you need '%(prog)s' to use a specific compiler for
- *compilation* then you can use this option to specify a path
- to that compiler.""")
- advanced.add_argument(
- '--use-c++',
- metavar='<path>',
- dest='cxx',
- default='c++',
- help="""This is the same as "--use-cc" but for C++ code.""")
-
- parser.add_argument(
- dest='build',
- nargs=argparse.REMAINDER,
- help="""Command to run.""")
-
- return parser
diff --git a/tools/scan-build-py/libscanbuild/report.py b/tools/scan-build-py/libscanbuild/report.py
index 766ddef71990..54b9695d927f 100644
--- a/tools/scan-build-py/libscanbuild/report.py
+++ b/tools/scan-build-py/libscanbuild/report.py
@@ -13,102 +13,65 @@ import os
import os.path
import sys
import shutil
-import time
-import tempfile
import itertools
import plistlib
import glob
import json
import logging
-import contextlib
import datetime
from libscanbuild import duplicate_check
from libscanbuild.clang import get_version
-__all__ = ['report_directory', 'document']
+__all__ = ['document']
-@contextlib.contextmanager
-def report_directory(hint, keep):
- """ Responsible for the report directory.
-
- hint -- could specify the parent directory of the output directory.
- keep -- a boolean value to keep or delete the empty report directory. """
-
- stamp_format = 'scan-build-%Y-%m-%d-%H-%M-%S-%f-'
- stamp = datetime.datetime.now().strftime(stamp_format)
-
- parentdir = os.path.abspath(hint)
- if not os.path.exists(parentdir):
- os.makedirs(parentdir)
-
- name = tempfile.mkdtemp(prefix=stamp, dir=parentdir)
-
- logging.info('Report directory created: %s', name)
-
- try:
- yield name
- finally:
- if os.listdir(name):
- msg = "Run 'scan-view %s' to examine bug reports."
- keep = True
- else:
- if keep:
- msg = "Report directory '%s' contans no report, but kept."
- else:
- msg = "Removing directory '%s' because it contains no report."
- logging.warning(msg, name)
-
- if not keep:
- os.rmdir(name)
-
-
-def document(args, output_dir, use_cdb):
+def document(args):
""" Generates cover report and returns the number of bugs/crashes. """
html_reports_available = args.output_format in {'html', 'plist-html'}
logging.debug('count crashes and bugs')
- crash_count = sum(1 for _ in read_crashes(output_dir))
+ crash_count = sum(1 for _ in read_crashes(args.output))
bug_counter = create_counters()
- for bug in read_bugs(output_dir, html_reports_available):
+ for bug in read_bugs(args.output, html_reports_available):
bug_counter(bug)
result = crash_count + bug_counter.total
if html_reports_available and result:
+ use_cdb = os.path.exists(args.cdb)
+
logging.debug('generate index.html file')
- # common prefix for source files to have sort filenames
+ # common prefix for source files to have sorter path
prefix = commonprefix_from(args.cdb) if use_cdb else os.getcwd()
# assemble the cover from multiple fragments
+ fragments = []
try:
- fragments = []
if bug_counter.total:
- fragments.append(bug_summary(output_dir, bug_counter))
- fragments.append(bug_report(output_dir, prefix))
+ fragments.append(bug_summary(args.output, bug_counter))
+ fragments.append(bug_report(args.output, prefix))
if crash_count:
- fragments.append(crash_report(output_dir, prefix))
- assemble_cover(output_dir, prefix, args, fragments)
- # copy additinal files to the report
- copy_resource_files(output_dir)
+ fragments.append(crash_report(args.output, prefix))
+ assemble_cover(args, prefix, fragments)
+ # copy additional files to the report
+ copy_resource_files(args.output)
if use_cdb:
- shutil.copy(args.cdb, output_dir)
+ shutil.copy(args.cdb, args.output)
finally:
for fragment in fragments:
os.remove(fragment)
return result
-def assemble_cover(output_dir, prefix, args, fragments):
+def assemble_cover(args, prefix, fragments):
""" Put together the fragments into a final report. """
import getpass
import socket
- import datetime
if args.html_title is None:
args.html_title = os.path.basename(prefix) + ' - analyzer results'
- with open(os.path.join(output_dir, 'index.html'), 'w') as handle:
+ with open(os.path.join(args.output, 'index.html'), 'w') as handle:
indent = 0
handle.write(reindent("""
|<!DOCTYPE html>
@@ -375,11 +338,12 @@ def parse_crash(filename):
match = re.match(r'(.*)\.info\.txt', filename)
name = match.group(1) if match else None
- with open(filename) as handler:
- lines = handler.readlines()
+ with open(filename, mode='rb') as handler:
+ # this is a workaround to fix windows read '\r\n' as new lines.
+ lines = [line.decode().rstrip() for line in handler.readlines()]
return {
- 'source': lines[0].rstrip(),
- 'problem': lines[1].rstrip(),
+ 'source': lines[0],
+ 'problem': lines[1],
'file': name,
'info': name + '.info.txt',
'stderr': name + '.stderr.txt'
@@ -519,9 +483,10 @@ def commonprefix_from(filename):
def commonprefix(files):
- """ Fixed version of os.path.commonprefix. Return the longest path prefix
- that is a prefix of all paths in filenames. """
+ """ Fixed version of os.path.commonprefix.
+ :param files: list of file names.
+ :return: the longest path prefix that is a prefix of all files. """
result = None
for current in files:
if result is not None:
diff --git a/tools/scan-build-py/libscanbuild/runner.py b/tools/scan-build-py/libscanbuild/runner.py
deleted file mode 100644
index 72d02c85fed1..000000000000
--- a/tools/scan-build-py/libscanbuild/runner.py
+++ /dev/null
@@ -1,302 +0,0 @@
-# -*- coding: utf-8 -*-
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-""" This module is responsible to run the analyzer commands. """
-
-import re
-import os
-import os.path
-import tempfile
-import functools
-import subprocess
-import logging
-from libscanbuild.compilation import classify_source, compiler_language
-from libscanbuild.clang import get_version, get_arguments
-from libscanbuild.shell import decode
-
-__all__ = ['run']
-
-# To have good results from static analyzer certain compiler options shall be
-# omitted. The compiler flag filtering only affects the static analyzer run.
-#
-# Keys are the option name, value number of options to skip
-IGNORED_FLAGS = {
- '-c': 0, # compile option will be overwritten
- '-fsyntax-only': 0, # static analyzer option will be overwritten
- '-o': 1, # will set up own output file
- # flags below are inherited from the perl implementation.
- '-g': 0,
- '-save-temps': 0,
- '-install_name': 1,
- '-exported_symbols_list': 1,
- '-current_version': 1,
- '-compatibility_version': 1,
- '-init': 1,
- '-e': 1,
- '-seg1addr': 1,
- '-bundle_loader': 1,
- '-multiply_defined': 1,
- '-sectorder': 3,
- '--param': 1,
- '--serialize-diagnostics': 1
-}
-
-
-def require(required):
- """ Decorator for checking the required values in state.
-
- It checks the required attributes in the passed state and stop when
- any of those is missing. """
-
- def decorator(function):
- @functools.wraps(function)
- def wrapper(*args, **kwargs):
- for key in required:
- if key not in args[0]:
- raise KeyError('{0} not passed to {1}'.format(
- key, function.__name__))
-
- return function(*args, **kwargs)
-
- return wrapper
-
- return decorator
-
-
-@require(['command', # entry from compilation database
- 'directory', # entry from compilation database
- 'file', # entry from compilation database
- 'clang', # clang executable name (and path)
- 'direct_args', # arguments from command line
- 'force_debug', # kill non debug macros
- 'output_dir', # where generated report files shall go
- 'output_format', # it's 'plist' or 'html' or both
- 'output_failures']) # generate crash reports or not
-def run(opts):
- """ Entry point to run (or not) static analyzer against a single entry
- of the compilation database.
-
- This complex task is decomposed into smaller methods which are calling
- each other in chain. If the analyzis is not possibe the given method
- just return and break the chain.
-
- The passed parameter is a python dictionary. Each method first check
- that the needed parameters received. (This is done by the 'require'
- decorator. It's like an 'assert' to check the contract between the
- caller and the called method.) """
-
- try:
- command = opts.pop('command')
- command = command if isinstance(command, list) else decode(command)
- logging.debug("Run analyzer against '%s'", command)
- opts.update(classify_parameters(command))
-
- return arch_check(opts)
- except Exception:
- logging.error("Problem occured during analyzis.", exc_info=1)
- return None
-
-
-@require(['clang', 'directory', 'flags', 'file', 'output_dir', 'language',
- 'error_type', 'error_output', 'exit_code'])
-def report_failure(opts):
- """ Create report when analyzer failed.
-
- The major report is the preprocessor output. The output filename generated
- randomly. The compiler output also captured into '.stderr.txt' file.
- And some more execution context also saved into '.info.txt' file. """
-
- def extension(opts):
- """ Generate preprocessor file extension. """
-
- mapping = {'objective-c++': '.mii', 'objective-c': '.mi', 'c++': '.ii'}
- return mapping.get(opts['language'], '.i')
-
- def destination(opts):
- """ Creates failures directory if not exits yet. """
-
- name = os.path.join(opts['output_dir'], 'failures')
- if not os.path.isdir(name):
- os.makedirs(name)
- return name
-
- error = opts['error_type']
- (handle, name) = tempfile.mkstemp(suffix=extension(opts),
- prefix='clang_' + error + '_',
- dir=destination(opts))
- os.close(handle)
- cwd = opts['directory']
- cmd = get_arguments([opts['clang'], '-fsyntax-only', '-E'] +
- opts['flags'] + [opts['file'], '-o', name], cwd)
- logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
- subprocess.call(cmd, cwd=cwd)
- # write general information about the crash
- with open(name + '.info.txt', 'w') as handle:
- handle.write(opts['file'] + os.linesep)
- handle.write(error.title().replace('_', ' ') + os.linesep)
- handle.write(' '.join(cmd) + os.linesep)
- handle.write(' '.join(os.uname()) + os.linesep)
- handle.write(get_version(opts['clang']))
- handle.close()
- # write the captured output too
- with open(name + '.stderr.txt', 'w') as handle:
- handle.writelines(opts['error_output'])
- handle.close()
- # return with the previous step exit code and output
- return {
- 'error_output': opts['error_output'],
- 'exit_code': opts['exit_code']
- }
-
-
-@require(['clang', 'directory', 'flags', 'direct_args', 'file', 'output_dir',
- 'output_format'])
-def run_analyzer(opts, continuation=report_failure):
- """ It assembles the analysis command line and executes it. Capture the
- output of the analysis and returns with it. If failure reports are
- requested, it calls the continuation to generate it. """
-
- def output():
- """ Creates output file name for reports. """
- if opts['output_format'] in {'plist', 'plist-html'}:
- (handle, name) = tempfile.mkstemp(prefix='report-',
- suffix='.plist',
- dir=opts['output_dir'])
- os.close(handle)
- return name
- return opts['output_dir']
-
- cwd = opts['directory']
- cmd = get_arguments([opts['clang'], '--analyze'] + opts['direct_args'] +
- opts['flags'] + [opts['file'], '-o', output()],
- cwd)
- logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
- child = subprocess.Popen(cmd,
- cwd=cwd,
- universal_newlines=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- output = child.stdout.readlines()
- child.stdout.close()
- # do report details if it were asked
- child.wait()
- if opts.get('output_failures', False) and child.returncode:
- error_type = 'crash' if child.returncode & 127 else 'other_error'
- opts.update({
- 'error_type': error_type,
- 'error_output': output,
- 'exit_code': child.returncode
- })
- return continuation(opts)
- # return the output for logging and exit code for testing
- return {'error_output': output, 'exit_code': child.returncode}
-
-
-@require(['flags', 'force_debug'])
-def filter_debug_flags(opts, continuation=run_analyzer):
- """ Filter out nondebug macros when requested. """
-
- if opts.pop('force_debug'):
- # lazy implementation just append an undefine macro at the end
- opts.update({'flags': opts['flags'] + ['-UNDEBUG']})
-
- return continuation(opts)
-
-
-@require(['language', 'compiler', 'file', 'flags'])
-def language_check(opts, continuation=filter_debug_flags):
- """ Find out the language from command line parameters or file name
- extension. The decision also influenced by the compiler invocation. """
-
- accepted = frozenset({
- 'c', 'c++', 'objective-c', 'objective-c++', 'c-cpp-output',
- 'c++-cpp-output', 'objective-c-cpp-output'
- })
-
- # language can be given as a parameter...
- language = opts.pop('language')
- compiler = opts.pop('compiler')
- # ... or find out from source file extension
- if language is None and compiler is not None:
- language = classify_source(opts['file'], compiler == 'c')
-
- if language is None:
- logging.debug('skip analysis, language not known')
- return None
- elif language not in accepted:
- logging.debug('skip analysis, language not supported')
- return None
- else:
- logging.debug('analysis, language: %s', language)
- opts.update({'language': language,
- 'flags': ['-x', language] + opts['flags']})
- return continuation(opts)
-
-
-@require(['arch_list', 'flags'])
-def arch_check(opts, continuation=language_check):
- """ Do run analyzer through one of the given architectures. """
-
- disabled = frozenset({'ppc', 'ppc64'})
-
- received_list = opts.pop('arch_list')
- if received_list:
- # filter out disabled architectures and -arch switches
- filtered_list = [a for a in received_list if a not in disabled]
- if filtered_list:
- # There should be only one arch given (or the same multiple
- # times). If there are multiple arch are given and are not
- # the same, those should not change the pre-processing step.
- # But that's the only pass we have before run the analyzer.
- current = filtered_list.pop()
- logging.debug('analysis, on arch: %s', current)
-
- opts.update({'flags': ['-arch', current] + opts['flags']})
- return continuation(opts)
- else:
- logging.debug('skip analysis, found not supported arch')
- return None
- else:
- logging.debug('analysis, on default arch')
- return continuation(opts)
-
-
-def classify_parameters(command):
- """ Prepare compiler flags (filters some and add others) and take out
- language (-x) and architecture (-arch) flags for future processing. """
-
- result = {
- 'flags': [], # the filtered compiler flags
- 'arch_list': [], # list of architecture flags
- 'language': None, # compilation language, None, if not specified
- 'compiler': compiler_language(command) # 'c' or 'c++'
- }
-
- # iterate on the compile options
- args = iter(command[1:])
- for arg in args:
- # take arch flags into a separate basket
- if arg == '-arch':
- result['arch_list'].append(next(args))
- # take language
- elif arg == '-x':
- result['language'] = next(args)
- # parameters which looks source file are not flags
- elif re.match(r'^[^-].+', arg) and classify_source(arg):
- pass
- # ignore some flags
- elif arg in IGNORED_FLAGS:
- count = IGNORED_FLAGS[arg]
- for _ in range(count):
- next(args)
- # we don't care about extra warnings, but we should suppress ones
- # that we don't want to see.
- elif re.match(r'^-W.+', arg) and not re.match(r'^-Wno-.+', arg):
- pass
- # and consider everything else as compilation flag.
- else:
- result['flags'].append(arg)
-
- return result
diff --git a/tools/scan-build-py/tests/unit/__init__.py b/tools/scan-build-py/tests/unit/__init__.py
index dc8bf12eb47c..6b7fd9fa0d02 100644
--- a/tools/scan-build-py/tests/unit/__init__.py
+++ b/tools/scan-build-py/tests/unit/__init__.py
@@ -7,7 +7,6 @@
from . import test_libear
from . import test_compilation
from . import test_clang
-from . import test_runner
from . import test_report
from . import test_analyze
from . import test_intercept
@@ -18,7 +17,6 @@ def load_tests(loader, suite, _):
suite.addTests(loader.loadTestsFromModule(test_libear))
suite.addTests(loader.loadTestsFromModule(test_compilation))
suite.addTests(loader.loadTestsFromModule(test_clang))
- suite.addTests(loader.loadTestsFromModule(test_runner))
suite.addTests(loader.loadTestsFromModule(test_report))
suite.addTests(loader.loadTestsFromModule(test_analyze))
suite.addTests(loader.loadTestsFromModule(test_intercept))
diff --git a/tools/scan-build-py/tests/unit/test_analyze.py b/tools/scan-build-py/tests/unit/test_analyze.py
index 481cc0c0993b..a250ff22132c 100644
--- a/tools/scan-build-py/tests/unit/test_analyze.py
+++ b/tools/scan-build-py/tests/unit/test_analyze.py
@@ -4,4 +4,332 @@
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
+import libear
import libscanbuild.analyze as sut
+import unittest
+import re
+import os
+import os.path
+
+
+class ReportDirectoryTest(unittest.TestCase):
+
+ # Test that successive report directory names ascend in lexicographic
+ # order. This is required so that report directories from two runs of
+ # scan-build can be easily matched up to compare results.
+ def test_directory_name_comparison(self):
+ with libear.TemporaryDirectory() as tmpdir, \
+ sut.report_directory(tmpdir, False) as report_dir1, \
+ sut.report_directory(tmpdir, False) as report_dir2, \
+ sut.report_directory(tmpdir, False) as report_dir3:
+ self.assertLess(report_dir1, report_dir2)
+ self.assertLess(report_dir2, report_dir3)
+
+
+class FilteringFlagsTest(unittest.TestCase):
+
+ def test_language_captured(self):
+ def test(flags):
+ cmd = ['clang', '-c', 'source.c'] + flags
+ opts = sut.classify_parameters(cmd)
+ return opts['language']
+
+ self.assertEqual(None, test([]))
+ self.assertEqual('c', test(['-x', 'c']))
+ self.assertEqual('cpp', test(['-x', 'cpp']))
+
+ def test_arch(self):
+ def test(flags):
+ cmd = ['clang', '-c', 'source.c'] + flags
+ opts = sut.classify_parameters(cmd)
+ return opts['arch_list']
+
+ self.assertEqual([], test([]))
+ self.assertEqual(['mips'], test(['-arch', 'mips']))
+ self.assertEqual(['mips', 'i386'],
+ test(['-arch', 'mips', '-arch', 'i386']))
+
+ def assertFlagsChanged(self, expected, flags):
+ cmd = ['clang', '-c', 'source.c'] + flags
+ opts = sut.classify_parameters(cmd)
+ self.assertEqual(expected, opts['flags'])
+
+ def assertFlagsUnchanged(self, flags):
+ self.assertFlagsChanged(flags, flags)
+
+ def assertFlagsFiltered(self, flags):
+ self.assertFlagsChanged([], flags)
+
+ def test_optimalizations_pass(self):
+ self.assertFlagsUnchanged(['-O'])
+ self.assertFlagsUnchanged(['-O1'])
+ self.assertFlagsUnchanged(['-Os'])
+ self.assertFlagsUnchanged(['-O2'])
+ self.assertFlagsUnchanged(['-O3'])
+
+ def test_include_pass(self):
+ self.assertFlagsUnchanged([])
+ self.assertFlagsUnchanged(['-include', '/usr/local/include'])
+ self.assertFlagsUnchanged(['-I.'])
+ self.assertFlagsUnchanged(['-I', '.'])
+ self.assertFlagsUnchanged(['-I/usr/local/include'])
+ self.assertFlagsUnchanged(['-I', '/usr/local/include'])
+ self.assertFlagsUnchanged(['-I/opt', '-I', '/opt/otp/include'])
+ self.assertFlagsUnchanged(['-isystem', '/path'])
+ self.assertFlagsUnchanged(['-isystem=/path'])
+
+ def test_define_pass(self):
+ self.assertFlagsUnchanged(['-DNDEBUG'])
+ self.assertFlagsUnchanged(['-UNDEBUG'])
+ self.assertFlagsUnchanged(['-Dvar1=val1', '-Dvar2=val2'])
+ self.assertFlagsUnchanged(['-Dvar="val ues"'])
+
+ def test_output_filtered(self):
+ self.assertFlagsFiltered(['-o', 'source.o'])
+
+ def test_some_warning_filtered(self):
+ self.assertFlagsFiltered(['-Wall'])
+ self.assertFlagsFiltered(['-Wnoexcept'])
+ self.assertFlagsFiltered(['-Wreorder', '-Wunused', '-Wundef'])
+ self.assertFlagsUnchanged(['-Wno-reorder', '-Wno-unused'])
+
+ def test_compile_only_flags_pass(self):
+ self.assertFlagsUnchanged(['-std=C99'])
+ self.assertFlagsUnchanged(['-nostdinc'])
+ self.assertFlagsUnchanged(['-isystem', '/image/debian'])
+ self.assertFlagsUnchanged(['-iprefix', '/usr/local'])
+ self.assertFlagsUnchanged(['-iquote=me'])
+ self.assertFlagsUnchanged(['-iquote', 'me'])
+
+ def test_compile_and_link_flags_pass(self):
+ self.assertFlagsUnchanged(['-fsinged-char'])
+ self.assertFlagsUnchanged(['-fPIC'])
+ self.assertFlagsUnchanged(['-stdlib=libc++'])
+ self.assertFlagsUnchanged(['--sysroot', '/'])
+ self.assertFlagsUnchanged(['-isysroot', '/'])
+
+ def test_some_flags_filtered(self):
+ self.assertFlagsFiltered(['-g'])
+ self.assertFlagsFiltered(['-fsyntax-only'])
+ self.assertFlagsFiltered(['-save-temps'])
+ self.assertFlagsFiltered(['-init', 'my_init'])
+ self.assertFlagsFiltered(['-sectorder', 'a', 'b', 'c'])
+
+
+class Spy(object):
+ def __init__(self):
+ self.arg = None
+ self.success = 0
+
+ def call(self, params):
+ self.arg = params
+ return self.success
+
+
+class RunAnalyzerTest(unittest.TestCase):
+
+ @staticmethod
+ def run_analyzer(content, failures_report):
+ with libear.TemporaryDirectory() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.cpp')
+ with open(filename, 'w') as handle:
+ handle.write(content)
+
+ opts = {
+ 'clang': 'clang',
+ 'directory': os.getcwd(),
+ 'flags': [],
+ 'direct_args': [],
+ 'file': filename,
+ 'output_dir': tmpdir,
+ 'output_format': 'plist',
+ 'output_failures': failures_report
+ }
+ spy = Spy()
+ result = sut.run_analyzer(opts, spy.call)
+ return (result, spy.arg)
+
+ def test_run_analyzer(self):
+ content = "int div(int n, int d) { return n / d; }"
+ (result, fwds) = RunAnalyzerTest.run_analyzer(content, False)
+ self.assertEqual(None, fwds)
+ self.assertEqual(0, result['exit_code'])
+
+ def test_run_analyzer_crash(self):
+ content = "int div(int n, int d) { return n / d }"
+ (result, fwds) = RunAnalyzerTest.run_analyzer(content, False)
+ self.assertEqual(None, fwds)
+ self.assertEqual(1, result['exit_code'])
+
+ def test_run_analyzer_crash_and_forwarded(self):
+ content = "int div(int n, int d) { return n / d }"
+ (_, fwds) = RunAnalyzerTest.run_analyzer(content, True)
+ self.assertEqual(1, fwds['exit_code'])
+ self.assertTrue(len(fwds['error_output']) > 0)
+
+
+class ReportFailureTest(unittest.TestCase):
+
+ def assertUnderFailures(self, path):
+ self.assertEqual('failures', os.path.basename(os.path.dirname(path)))
+
+ def test_report_failure_create_files(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ # create input file
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('int main() { return 0')
+ uname_msg = ' '.join(os.uname()) + os.linesep
+ error_msg = 'this is my error output'
+ # execute test
+ opts = {
+ 'clang': 'clang',
+ 'directory': os.getcwd(),
+ 'flags': [],
+ 'file': filename,
+ 'output_dir': tmpdir,
+ 'language': 'c',
+ 'error_type': 'other_error',
+ 'error_output': error_msg,
+ 'exit_code': 13
+ }
+ sut.report_failure(opts)
+ # verify the result
+ result = dict()
+ pp_file = None
+ for root, _, files in os.walk(tmpdir):
+ keys = [os.path.join(root, name) for name in files]
+ for key in keys:
+ with open(key, 'r') as handle:
+ result[key] = handle.readlines()
+ if re.match(r'^(.*/)+clang(.*)\.i$', key):
+ pp_file = key
+
+ # prepocessor file generated
+ self.assertUnderFailures(pp_file)
+ # info file generated and content dumped
+ info_file = pp_file + '.info.txt'
+ self.assertTrue(info_file in result)
+ self.assertEqual('Other Error\n', result[info_file][1])
+ self.assertEqual(uname_msg, result[info_file][3])
+ # error file generated and content dumped
+ error_file = pp_file + '.stderr.txt'
+ self.assertTrue(error_file in result)
+ self.assertEqual([error_msg], result[error_file])
+
+
+class AnalyzerTest(unittest.TestCase):
+
+ def test_nodebug_macros_appended(self):
+ def test(flags):
+ spy = Spy()
+ opts = {'flags': flags, 'force_debug': True}
+ self.assertEqual(spy.success,
+ sut.filter_debug_flags(opts, spy.call))
+ return spy.arg['flags']
+
+ self.assertEqual(['-UNDEBUG'], test([]))
+ self.assertEqual(['-DNDEBUG', '-UNDEBUG'], test(['-DNDEBUG']))
+ self.assertEqual(['-DSomething', '-UNDEBUG'], test(['-DSomething']))
+
+ def test_set_language_fall_through(self):
+ def language(expected, input):
+ spy = Spy()
+ input.update({'compiler': 'c', 'file': 'test.c'})
+ self.assertEqual(spy.success, sut.language_check(input, spy.call))
+ self.assertEqual(expected, spy.arg['language'])
+
+ language('c', {'language': 'c', 'flags': []})
+ language('c++', {'language': 'c++', 'flags': []})
+
+ def test_set_language_stops_on_not_supported(self):
+ spy = Spy()
+ input = {
+ 'compiler': 'c',
+ 'flags': [],
+ 'file': 'test.java',
+ 'language': 'java'
+ }
+ self.assertIsNone(sut.language_check(input, spy.call))
+ self.assertIsNone(spy.arg)
+
+ def test_set_language_sets_flags(self):
+ def flags(expected, input):
+ spy = Spy()
+ input.update({'compiler': 'c', 'file': 'test.c'})
+ self.assertEqual(spy.success, sut.language_check(input, spy.call))
+ self.assertEqual(expected, spy.arg['flags'])
+
+ flags(['-x', 'c'], {'language': 'c', 'flags': []})
+ flags(['-x', 'c++'], {'language': 'c++', 'flags': []})
+
+ def test_set_language_from_filename(self):
+ def language(expected, input):
+ spy = Spy()
+ input.update({'language': None, 'flags': []})
+ self.assertEqual(spy.success, sut.language_check(input, spy.call))
+ self.assertEqual(expected, spy.arg['language'])
+
+ language('c', {'file': 'file.c', 'compiler': 'c'})
+ language('c++', {'file': 'file.c', 'compiler': 'c++'})
+ language('c++', {'file': 'file.cxx', 'compiler': 'c'})
+ language('c++', {'file': 'file.cxx', 'compiler': 'c++'})
+ language('c++', {'file': 'file.cpp', 'compiler': 'c++'})
+ language('c-cpp-output', {'file': 'file.i', 'compiler': 'c'})
+ language('c++-cpp-output', {'file': 'file.i', 'compiler': 'c++'})
+
+ def test_arch_loop_sets_flags(self):
+ def flags(archs):
+ spy = Spy()
+ input = {'flags': [], 'arch_list': archs}
+ sut.arch_check(input, spy.call)
+ return spy.arg['flags']
+
+ self.assertEqual([], flags([]))
+ self.assertEqual(['-arch', 'i386'], flags(['i386']))
+ self.assertEqual(['-arch', 'i386'], flags(['i386', 'ppc']))
+ self.assertEqual(['-arch', 'sparc'], flags(['i386', 'sparc']))
+
+ def test_arch_loop_stops_on_not_supported(self):
+ def stop(archs):
+ spy = Spy()
+ input = {'flags': [], 'arch_list': archs}
+ self.assertIsNone(sut.arch_check(input, spy.call))
+ self.assertIsNone(spy.arg)
+
+ stop(['ppc'])
+ stop(['ppc64'])
+
+
+@sut.require([])
+def method_without_expecteds(opts):
+ return 0
+
+
+@sut.require(['this', 'that'])
+def method_with_expecteds(opts):
+ return 0
+
+
+@sut.require([])
+def method_exception_from_inside(opts):
+ raise Exception('here is one')
+
+
+class RequireDecoratorTest(unittest.TestCase):
+
+ def test_method_without_expecteds(self):
+ self.assertEqual(method_without_expecteds(dict()), 0)
+ self.assertEqual(method_without_expecteds({}), 0)
+ self.assertEqual(method_without_expecteds({'this': 2}), 0)
+ self.assertEqual(method_without_expecteds({'that': 3}), 0)
+
+ def test_method_with_expecteds(self):
+ self.assertRaises(KeyError, method_with_expecteds, dict())
+ self.assertRaises(KeyError, method_with_expecteds, {})
+ self.assertRaises(KeyError, method_with_expecteds, {'this': 2})
+ self.assertRaises(KeyError, method_with_expecteds, {'that': 3})
+ self.assertEqual(method_with_expecteds({'this': 0, 'that': 3}), 0)
+
+ def test_method_exception_not_caught(self):
+ self.assertRaises(Exception, method_exception_from_inside, dict())
diff --git a/tools/scan-build-py/tests/unit/test_intercept.py b/tools/scan-build-py/tests/unit/test_intercept.py
index 5b6ed2cee1f6..583d1c3da979 100644
--- a/tools/scan-build-py/tests/unit/test_intercept.py
+++ b/tools/scan-build-py/tests/unit/test_intercept.py
@@ -65,11 +65,10 @@ class InterceptUtilTest(unittest.TestCase):
DISABLED = 'disabled'
OSX = 'darwin'
- LINUX = 'linux'
with libear.TemporaryDirectory() as tmpdir:
+ saved = os.environ['PATH']
try:
- saved = os.environ['PATH']
os.environ['PATH'] = tmpdir + ':' + saved
create_csrutil(tmpdir, ENABLED)
@@ -77,21 +76,14 @@ class InterceptUtilTest(unittest.TestCase):
create_csrutil(tmpdir, DISABLED)
self.assertFalse(sut.is_preload_disabled(OSX))
-
- create_sestatus(tmpdir, ENABLED)
- self.assertTrue(sut.is_preload_disabled(LINUX))
-
- create_sestatus(tmpdir, DISABLED)
- self.assertFalse(sut.is_preload_disabled(LINUX))
finally:
os.environ['PATH'] = saved
+ saved = os.environ['PATH']
try:
- saved = os.environ['PATH']
os.environ['PATH'] = ''
# shall be false when it's not in the path
self.assertFalse(sut.is_preload_disabled(OSX))
- self.assertFalse(sut.is_preload_disabled(LINUX))
self.assertFalse(sut.is_preload_disabled('unix'))
finally:
diff --git a/tools/scan-build-py/tests/unit/test_report.py b/tools/scan-build-py/tests/unit/test_report.py
index c82b5593e0dc..c9436991561d 100644
--- a/tools/scan-build-py/tests/unit/test_report.py
+++ b/tools/scan-build-py/tests/unit/test_report.py
@@ -75,7 +75,7 @@ class ParseFileTest(unittest.TestCase):
'file.i.stderr.txt')
def test_parse_real_crash(self):
- import libscanbuild.runner as sut2
+ import libscanbuild.analyze as sut2
import re
with libear.TemporaryDirectory() as tmpdir:
filename = os.path.join(tmpdir, 'test.c')
@@ -146,16 +146,3 @@ class GetPrefixFromCompilationDatabaseTest(unittest.TestCase):
def test_empty(self):
self.assertEqual(
sut.commonprefix([]), '')
-
-class ReportDirectoryTest(unittest.TestCase):
-
- # Test that successive report directory names ascend in lexicographic
- # order. This is required so that report directories from two runs of
- # scan-build can be easily matched up to compare results.
- def test_directory_name_comparison(self):
- with libear.TemporaryDirectory() as tmpdir, \
- sut.report_directory(tmpdir, False) as report_dir1, \
- sut.report_directory(tmpdir, False) as report_dir2, \
- sut.report_directory(tmpdir, False) as report_dir3:
- self.assertLess(report_dir1, report_dir2)
- self.assertLess(report_dir2, report_dir3)
diff --git a/tools/scan-build-py/tests/unit/test_runner.py b/tools/scan-build-py/tests/unit/test_runner.py
deleted file mode 100644
index 2d0906223329..000000000000
--- a/tools/scan-build-py/tests/unit/test_runner.py
+++ /dev/null
@@ -1,322 +0,0 @@
-# -*- coding: utf-8 -*-
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-
-import libear
-import libscanbuild.runner as sut
-import unittest
-import re
-import os
-import os.path
-
-
-class FilteringFlagsTest(unittest.TestCase):
-
- def test_language_captured(self):
- def test(flags):
- cmd = ['clang', '-c', 'source.c'] + flags
- opts = sut.classify_parameters(cmd)
- return opts['language']
-
- self.assertEqual(None, test([]))
- self.assertEqual('c', test(['-x', 'c']))
- self.assertEqual('cpp', test(['-x', 'cpp']))
-
- def test_arch(self):
- def test(flags):
- cmd = ['clang', '-c', 'source.c'] + flags
- opts = sut.classify_parameters(cmd)
- return opts['arch_list']
-
- self.assertEqual([], test([]))
- self.assertEqual(['mips'], test(['-arch', 'mips']))
- self.assertEqual(['mips', 'i386'],
- test(['-arch', 'mips', '-arch', 'i386']))
-
- def assertFlagsChanged(self, expected, flags):
- cmd = ['clang', '-c', 'source.c'] + flags
- opts = sut.classify_parameters(cmd)
- self.assertEqual(expected, opts['flags'])
-
- def assertFlagsUnchanged(self, flags):
- self.assertFlagsChanged(flags, flags)
-
- def assertFlagsFiltered(self, flags):
- self.assertFlagsChanged([], flags)
-
- def test_optimalizations_pass(self):
- self.assertFlagsUnchanged(['-O'])
- self.assertFlagsUnchanged(['-O1'])
- self.assertFlagsUnchanged(['-Os'])
- self.assertFlagsUnchanged(['-O2'])
- self.assertFlagsUnchanged(['-O3'])
-
- def test_include_pass(self):
- self.assertFlagsUnchanged([])
- self.assertFlagsUnchanged(['-include', '/usr/local/include'])
- self.assertFlagsUnchanged(['-I.'])
- self.assertFlagsUnchanged(['-I', '.'])
- self.assertFlagsUnchanged(['-I/usr/local/include'])
- self.assertFlagsUnchanged(['-I', '/usr/local/include'])
- self.assertFlagsUnchanged(['-I/opt', '-I', '/opt/otp/include'])
- self.assertFlagsUnchanged(['-isystem', '/path'])
- self.assertFlagsUnchanged(['-isystem=/path'])
-
- def test_define_pass(self):
- self.assertFlagsUnchanged(['-DNDEBUG'])
- self.assertFlagsUnchanged(['-UNDEBUG'])
- self.assertFlagsUnchanged(['-Dvar1=val1', '-Dvar2=val2'])
- self.assertFlagsUnchanged(['-Dvar="val ues"'])
-
- def test_output_filtered(self):
- self.assertFlagsFiltered(['-o', 'source.o'])
-
- def test_some_warning_filtered(self):
- self.assertFlagsFiltered(['-Wall'])
- self.assertFlagsFiltered(['-Wnoexcept'])
- self.assertFlagsFiltered(['-Wreorder', '-Wunused', '-Wundef'])
- self.assertFlagsUnchanged(['-Wno-reorder', '-Wno-unused'])
-
- def test_compile_only_flags_pass(self):
- self.assertFlagsUnchanged(['-std=C99'])
- self.assertFlagsUnchanged(['-nostdinc'])
- self.assertFlagsUnchanged(['-isystem', '/image/debian'])
- self.assertFlagsUnchanged(['-iprefix', '/usr/local'])
- self.assertFlagsUnchanged(['-iquote=me'])
- self.assertFlagsUnchanged(['-iquote', 'me'])
-
- def test_compile_and_link_flags_pass(self):
- self.assertFlagsUnchanged(['-fsinged-char'])
- self.assertFlagsUnchanged(['-fPIC'])
- self.assertFlagsUnchanged(['-stdlib=libc++'])
- self.assertFlagsUnchanged(['--sysroot', '/'])
- self.assertFlagsUnchanged(['-isysroot', '/'])
-
- def test_some_flags_filtered(self):
- self.assertFlagsFiltered(['-g'])
- self.assertFlagsFiltered(['-fsyntax-only'])
- self.assertFlagsFiltered(['-save-temps'])
- self.assertFlagsFiltered(['-init', 'my_init'])
- self.assertFlagsFiltered(['-sectorder', 'a', 'b', 'c'])
-
-
-class Spy(object):
- def __init__(self):
- self.arg = None
- self.success = 0
-
- def call(self, params):
- self.arg = params
- return self.success
-
-
-class RunAnalyzerTest(unittest.TestCase):
-
- @staticmethod
- def run_analyzer(content, failures_report):
- with libear.TemporaryDirectory() as tmpdir:
- filename = os.path.join(tmpdir, 'test.cpp')
- with open(filename, 'w') as handle:
- handle.write(content)
-
- opts = {
- 'clang': 'clang',
- 'directory': os.getcwd(),
- 'flags': [],
- 'direct_args': [],
- 'file': filename,
- 'output_dir': tmpdir,
- 'output_format': 'plist',
- 'output_failures': failures_report
- }
- spy = Spy()
- result = sut.run_analyzer(opts, spy.call)
- return (result, spy.arg)
-
- def test_run_analyzer(self):
- content = "int div(int n, int d) { return n / d; }"
- (result, fwds) = RunAnalyzerTest.run_analyzer(content, False)
- self.assertEqual(None, fwds)
- self.assertEqual(0, result['exit_code'])
-
- def test_run_analyzer_crash(self):
- content = "int div(int n, int d) { return n / d }"
- (result, fwds) = RunAnalyzerTest.run_analyzer(content, False)
- self.assertEqual(None, fwds)
- self.assertEqual(1, result['exit_code'])
-
- def test_run_analyzer_crash_and_forwarded(self):
- content = "int div(int n, int d) { return n / d }"
- (_, fwds) = RunAnalyzerTest.run_analyzer(content, True)
- self.assertEqual('crash', fwds['error_type'])
- self.assertEqual(1, fwds['exit_code'])
- self.assertTrue(len(fwds['error_output']) > 0)
-
-
-class ReportFailureTest(unittest.TestCase):
-
- def assertUnderFailures(self, path):
- self.assertEqual('failures', os.path.basename(os.path.dirname(path)))
-
- def test_report_failure_create_files(self):
- with libear.TemporaryDirectory() as tmpdir:
- # create input file
- filename = os.path.join(tmpdir, 'test.c')
- with open(filename, 'w') as handle:
- handle.write('int main() { return 0')
- uname_msg = ' '.join(os.uname()) + os.linesep
- error_msg = 'this is my error output'
- # execute test
- opts = {
- 'clang': 'clang',
- 'directory': os.getcwd(),
- 'flags': [],
- 'file': filename,
- 'output_dir': tmpdir,
- 'language': 'c',
- 'error_type': 'other_error',
- 'error_output': error_msg,
- 'exit_code': 13
- }
- sut.report_failure(opts)
- # verify the result
- result = dict()
- pp_file = None
- for root, _, files in os.walk(tmpdir):
- keys = [os.path.join(root, name) for name in files]
- for key in keys:
- with open(key, 'r') as handle:
- result[key] = handle.readlines()
- if re.match(r'^(.*/)+clang(.*)\.i$', key):
- pp_file = key
-
- # prepocessor file generated
- self.assertUnderFailures(pp_file)
- # info file generated and content dumped
- info_file = pp_file + '.info.txt'
- self.assertTrue(info_file in result)
- self.assertEqual('Other Error\n', result[info_file][1])
- self.assertEqual(uname_msg, result[info_file][3])
- # error file generated and content dumped
- error_file = pp_file + '.stderr.txt'
- self.assertTrue(error_file in result)
- self.assertEqual([error_msg], result[error_file])
-
-
-class AnalyzerTest(unittest.TestCase):
-
- def test_nodebug_macros_appended(self):
- def test(flags):
- spy = Spy()
- opts = {'flags': flags, 'force_debug': True}
- self.assertEqual(spy.success,
- sut.filter_debug_flags(opts, spy.call))
- return spy.arg['flags']
-
- self.assertEqual(['-UNDEBUG'], test([]))
- self.assertEqual(['-DNDEBUG', '-UNDEBUG'], test(['-DNDEBUG']))
- self.assertEqual(['-DSomething', '-UNDEBUG'], test(['-DSomething']))
-
- def test_set_language_fall_through(self):
- def language(expected, input):
- spy = Spy()
- input.update({'compiler': 'c', 'file': 'test.c'})
- self.assertEqual(spy.success, sut.language_check(input, spy.call))
- self.assertEqual(expected, spy.arg['language'])
-
- language('c', {'language': 'c', 'flags': []})
- language('c++', {'language': 'c++', 'flags': []})
-
- def test_set_language_stops_on_not_supported(self):
- spy = Spy()
- input = {
- 'compiler': 'c',
- 'flags': [],
- 'file': 'test.java',
- 'language': 'java'
- }
- self.assertIsNone(sut.language_check(input, spy.call))
- self.assertIsNone(spy.arg)
-
- def test_set_language_sets_flags(self):
- def flags(expected, input):
- spy = Spy()
- input.update({'compiler': 'c', 'file': 'test.c'})
- self.assertEqual(spy.success, sut.language_check(input, spy.call))
- self.assertEqual(expected, spy.arg['flags'])
-
- flags(['-x', 'c'], {'language': 'c', 'flags': []})
- flags(['-x', 'c++'], {'language': 'c++', 'flags': []})
-
- def test_set_language_from_filename(self):
- def language(expected, input):
- spy = Spy()
- input.update({'language': None, 'flags': []})
- self.assertEqual(spy.success, sut.language_check(input, spy.call))
- self.assertEqual(expected, spy.arg['language'])
-
- language('c', {'file': 'file.c', 'compiler': 'c'})
- language('c++', {'file': 'file.c', 'compiler': 'c++'})
- language('c++', {'file': 'file.cxx', 'compiler': 'c'})
- language('c++', {'file': 'file.cxx', 'compiler': 'c++'})
- language('c++', {'file': 'file.cpp', 'compiler': 'c++'})
- language('c-cpp-output', {'file': 'file.i', 'compiler': 'c'})
- language('c++-cpp-output', {'file': 'file.i', 'compiler': 'c++'})
-
- def test_arch_loop_sets_flags(self):
- def flags(archs):
- spy = Spy()
- input = {'flags': [], 'arch_list': archs}
- sut.arch_check(input, spy.call)
- return spy.arg['flags']
-
- self.assertEqual([], flags([]))
- self.assertEqual(['-arch', 'i386'], flags(['i386']))
- self.assertEqual(['-arch', 'i386'], flags(['i386', 'ppc']))
- self.assertEqual(['-arch', 'sparc'], flags(['i386', 'sparc']))
-
- def test_arch_loop_stops_on_not_supported(self):
- def stop(archs):
- spy = Spy()
- input = {'flags': [], 'arch_list': archs}
- self.assertIsNone(sut.arch_check(input, spy.call))
- self.assertIsNone(spy.arg)
-
- stop(['ppc'])
- stop(['ppc64'])
-
-
-@sut.require([])
-def method_without_expecteds(opts):
- return 0
-
-
-@sut.require(['this', 'that'])
-def method_with_expecteds(opts):
- return 0
-
-
-@sut.require([])
-def method_exception_from_inside(opts):
- raise Exception('here is one')
-
-
-class RequireDecoratorTest(unittest.TestCase):
-
- def test_method_without_expecteds(self):
- self.assertEqual(method_without_expecteds(dict()), 0)
- self.assertEqual(method_without_expecteds({}), 0)
- self.assertEqual(method_without_expecteds({'this': 2}), 0)
- self.assertEqual(method_without_expecteds({'that': 3}), 0)
-
- def test_method_with_expecteds(self):
- self.assertRaises(KeyError, method_with_expecteds, dict())
- self.assertRaises(KeyError, method_with_expecteds, {})
- self.assertRaises(KeyError, method_with_expecteds, {'this': 2})
- self.assertRaises(KeyError, method_with_expecteds, {'that': 3})
- self.assertEqual(method_with_expecteds({'this': 0, 'that': 3}), 0)
-
- def test_method_exception_not_caught(self):
- self.assertRaises(Exception, method_exception_from_inside, dict())
diff --git a/tools/scan-build/CMakeLists.txt b/tools/scan-build/CMakeLists.txt
index 78c243d8e0d6..380379300b09 100644
--- a/tools/scan-build/CMakeLists.txt
+++ b/tools/scan-build/CMakeLists.txt
@@ -4,8 +4,11 @@ include(GNUInstallDirs)
if (WIN32 AND NOT CYGWIN)
set(BinFiles
+ scan-build
scan-build.bat)
set(LibexecFiles
+ ccc-analyzer
+ c++-analyzer
ccc-analyzer.bat
c++-analyzer.bat)
else()
diff --git a/tools/scan-view/share/Reporter.py b/tools/scan-view/share/Reporter.py
index 294e05b44c25..800af03b1a2c 100644
--- a/tools/scan-view/share/Reporter.py
+++ b/tools/scan-view/share/Reporter.py
@@ -1,3 +1,6 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
"""Methods for reporting bugs."""
import subprocess, sys, os
diff --git a/tools/scan-view/share/startfile.py b/tools/scan-view/share/startfile.py
index e8fbe2d5a84e..673935909f82 100644
--- a/tools/scan-view/share/startfile.py
+++ b/tools/scan-view/share/startfile.py
@@ -1,3 +1,6 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
"""Utility for opening a file using the default application in a cross-platform
manner. Modified from http://code.activestate.com/recipes/511443/.
"""
diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index dd45ca3ced92..5c29334222df 100644
--- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1494,15 +1494,32 @@ TEST(TypedefNameDeclMatcher, Match) {
typedefNameDecl(hasName("typedefNameDeclTest2"))));
}
+TEST(TypeAliasTemplateDeclMatcher, Match) {
+ std::string Code = R"(
+ template <typename T>
+ class X { T t; };
+
+ template <typename T>
+ using typeAliasTemplateDecl = X<T>;
+
+ using typeAliasDecl = X<int>;
+ )";
+ EXPECT_TRUE(
+ matches(Code, typeAliasTemplateDecl(hasName("typeAliasTemplateDecl"))));
+ EXPECT_TRUE(
+ notMatches(Code, typeAliasTemplateDecl(hasName("typeAliasDecl"))));
+}
+
TEST(ObjCMessageExprMatcher, SimpleExprs) {
// don't find ObjCMessageExpr where none are present
EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything())));
std::string Objc1String =
"@interface Str "
- " - (Str *)uppercaseString:(Str *)str;"
+ " - (Str *)uppercaseString;"
"@end "
"@interface foo "
+ "- (void)contents;"
"- (void)meth:(Str *)text;"
"@end "
" "
@@ -1540,5 +1557,45 @@ TEST(ObjCMessageExprMatcher, SimpleExprs) {
)));
}
+TEST(ObjCDeclMacher, CoreDecls) {
+ std::string ObjCString =
+ "@protocol Proto "
+ "- (void)protoDidThing; "
+ "@end "
+ "@interface Thing "
+ "@property int enabled; "
+ "@end "
+ "@interface Thing (ABC) "
+ "- (void)abc_doThing; "
+ "@end "
+ "@implementation Thing "
+ "{ id _ivar; } "
+ "- (void)anything {} "
+ "@end "
+ ;
+
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcProtocolDecl(hasName("Proto"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcCategoryDecl(hasName("ABC"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcMethodDecl(hasName("protoDidThing"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcMethodDecl(hasName("abc_doThing"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcMethodDecl(hasName("anything"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcIvarDecl(hasName("_ivar"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcPropertyDecl(hasName("enabled"))));
+}
+
} // namespace ast_matchers
} // namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index fdb273c672da..4f5579ce0def 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -61,7 +61,7 @@ private:
template <typename T>
testing::AssertionResult matchesConditionally(
const std::string &Code, const T &AMatcher, bool ExpectMatch,
- llvm::StringRef CompileArg,
+ llvm::ArrayRef<llvm::StringRef> CompileArgs,
const FileContentMappings &VirtualMappedFiles = FileContentMappings(),
const std::string &Filename = "input.cc") {
bool Found = false, DynamicFound = false;
@@ -81,8 +81,9 @@ testing::AssertionResult matchesConditionally(
// FIXME: This is a hack to work around the fact that there's no way to do the
// equivalent of runToolOnCodeWithArgs without instantiating a full Driver.
// We should consider having a function, at least for tests, that invokes cc1.
- std::vector<std::string> Args = {CompileArg, "-frtti", "-fexceptions",
- "-target", "i386-unknown-unknown"};
+ std::vector<std::string> Args(CompileArgs.begin(), CompileArgs.end());
+ Args.insert(Args.end(), {"-frtti", "-fexceptions",
+ "-target", "i386-unknown-unknown"});
if (!runToolOnCodeWithArgs(
Factory->create(), Code, Args, Filename, "clang-tool",
std::make_shared<PCHContainerOperations>(), VirtualMappedFiles)) {
@@ -105,6 +106,17 @@ testing::AssertionResult matchesConditionally(
}
template <typename T>
+testing::AssertionResult matchesConditionally(
+ const std::string &Code, const T &AMatcher, bool ExpectMatch,
+ llvm::StringRef CompileArg,
+ const FileContentMappings &VirtualMappedFiles = FileContentMappings(),
+ const std::string &Filename = "input.cc") {
+ return matchesConditionally(Code, AMatcher, ExpectMatch,
+ llvm::makeArrayRef(CompileArg),
+ VirtualMappedFiles, Filename);
+}
+
+template <typename T>
testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
return matchesConditionally(Code, AMatcher, true, "-std=c++11");
}
@@ -116,11 +128,12 @@ testing::AssertionResult notMatches(const std::string &Code,
}
template <typename T>
-testing::AssertionResult matchesObjC(const std::string &Code,
- const T &AMatcher) {
- return matchesConditionally(
- Code, AMatcher, true,
- "", FileContentMappings(), "input.m");
+testing::AssertionResult matchesObjC(const std::string &Code, const T &AMatcher,
+ bool ExpectMatch = true) {
+ return matchesConditionally(Code, AMatcher, ExpectMatch,
+ {"-fobjc-nonfragile-abi", "-Wno-objc-root-class",
+ "-Wno-incomplete-implementation"},
+ FileContentMappings(), "input.m");
}
template <typename T>
@@ -145,10 +158,8 @@ testing::AssertionResult notMatchesC(const std::string &Code,
template <typename T>
testing::AssertionResult notMatchesObjC(const std::string &Code,
- const T &AMatcher) {
- return matchesConditionally(
- Code, AMatcher, false,
- "", FileContentMappings(), "input.m");
+ const T &AMatcher) {
+ return matchesObjC(Code, AMatcher, false);
}
diff --git a/unittests/Analysis/CFGTest.cpp b/unittests/Analysis/CFGTest.cpp
index e691110050a2..768705f46f29 100644
--- a/unittests/Analysis/CFGTest.cpp
+++ b/unittests/Analysis/CFGTest.cpp
@@ -35,7 +35,9 @@ public:
if (!Body)
return;
TheBuildResult = SawFunctionBody;
- if (CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions()))
+ CFG::BuildOptions Options;
+ Options.AddImplicitDtors = true;
+ if (CFG::buildCFG(nullptr, Body, Result.Context, Options))
TheBuildResult = BuiltCFG;
}
};
@@ -75,6 +77,16 @@ TEST(CFG, DeleteExpressionOnDependentType) {
EXPECT_EQ(BuiltCFG, BuildCFG(Code));
}
+// Constructing a CFG on a function template with a variable of incomplete type
+// should not crash.
+TEST(CFG, VariableOfIncompleteType) {
+ const char *Code = "template<class T> void f() {\n"
+ " class Undefined;\n"
+ " Undefined u;\n"
+ "}\n";
+ EXPECT_EQ(BuiltCFG, BuildCFG(Code));
+}
+
} // namespace
} // namespace analysis
} // namespace clang
diff --git a/unittests/Analysis/CMakeLists.txt b/unittests/Analysis/CMakeLists.txt
index 926f586be3d6..62db8f652e11 100644
--- a/unittests/Analysis/CMakeLists.txt
+++ b/unittests/Analysis/CMakeLists.txt
@@ -2,11 +2,12 @@ set(LLVM_LINK_COMPONENTS
Support
)
-add_clang_unittest(CFGTests
+add_clang_unittest(ClangAnalysisTests
CFGTest.cpp
+ CloneDetectionTest.cpp
)
-target_link_libraries(CFGTests
+target_link_libraries(ClangAnalysisTests
clangAnalysis
clangAST
clangASTMatchers
diff --git a/unittests/Analysis/CloneDetectionTest.cpp b/unittests/Analysis/CloneDetectionTest.cpp
new file mode 100644
index 000000000000..6d8ce3495fa8
--- /dev/null
+++ b/unittests/Analysis/CloneDetectionTest.cpp
@@ -0,0 +1,110 @@
+//===- unittests/Analysis/CloneDetectionTest.cpp - Clone detection tests --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Analysis/CloneDetection.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace analysis {
+namespace {
+
+class CloneDetectionVisitor
+ : public RecursiveASTVisitor<CloneDetectionVisitor> {
+
+ CloneDetector &Detector;
+
+public:
+ explicit CloneDetectionVisitor(CloneDetector &D) : Detector(D) {}
+
+ bool VisitFunctionDecl(FunctionDecl *D) {
+ Detector.analyzeCodeBody(D);
+ return true;
+ }
+};
+
+/// Example constraint for testing purposes.
+/// Filters out all statements that are in a function which name starts with
+/// "bar".
+class NoBarFunctionConstraint {
+public:
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::splitCloneGroups(
+ CloneGroups, [](const StmtSequence &A, const StmtSequence &B) {
+ // Check if one of the sequences is in a function which name starts
+ // with "bar".
+ for (const StmtSequence &Arg : {A, B}) {
+ if (const auto *D =
+ dyn_cast<const FunctionDecl>(Arg.getContainingDecl())) {
+ if (D->getNameAsString().find("bar") == 0)
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+};
+
+TEST(CloneDetector, FilterFunctionsByName) {
+ auto ASTUnit =
+ clang::tooling::buildASTFromCode("void foo1(int &a1) { a1++; }\n"
+ "void foo2(int &a2) { a2++; }\n"
+ "void bar1(int &a3) { a3++; }\n"
+ "void bar2(int &a4) { a4++; }\n");
+ auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
+
+ CloneDetector Detector;
+ // Push all the function bodies into the detector.
+ CloneDetectionVisitor Visitor(Detector);
+ Visitor.TraverseTranslationUnitDecl(TU);
+
+ // Find clones with the usual settings, but but we want to filter out
+ // all statements from functions which names start with "bar".
+ std::vector<CloneDetector::CloneGroup> CloneGroups;
+ Detector.findClones(CloneGroups, NoBarFunctionConstraint(),
+ RecursiveCloneTypeIIConstraint(),
+ MinComplexityConstraint(2), MinGroupSizeConstraint(2),
+ OnlyLargestCloneConstraint());
+
+ ASSERT_EQ(CloneGroups.size(), 1u);
+ ASSERT_EQ(CloneGroups.front().size(), 2u);
+
+ for (auto &Clone : CloneGroups.front()) {
+ const auto ND = dyn_cast<const FunctionDecl>(Clone.getContainingDecl());
+ ASSERT_TRUE(ND != nullptr);
+ // Check that no function name starting with "bar" is in the results...
+ ASSERT_TRUE(ND->getNameAsString().find("bar") != 0);
+ }
+
+ // Retry above's example without the filter...
+ CloneGroups.clear();
+
+ Detector.findClones(CloneGroups, RecursiveCloneTypeIIConstraint(),
+ MinComplexityConstraint(2), MinGroupSizeConstraint(2),
+ OnlyLargestCloneConstraint());
+ ASSERT_EQ(CloneGroups.size(), 1u);
+ ASSERT_EQ(CloneGroups.front().size(), 4u);
+
+ // Count how many functions with the bar prefix we have in the results.
+ int FoundFunctionsWithBarPrefix = 0;
+ for (auto &Clone : CloneGroups.front()) {
+ const auto ND = dyn_cast<const FunctionDecl>(Clone.getContainingDecl());
+ ASSERT_TRUE(ND != nullptr);
+ // This time check that we picked up the bar functions from above
+ if (ND->getNameAsString().find("bar") == 0) {
+ FoundFunctionsWithBarPrefix++;
+ }
+ }
+ // We should have found the two functions bar1 and bar2.
+ ASSERT_EQ(FoundFunctionsWithBarPrefix, 2);
+}
+} // namespace
+} // namespace analysis
+} // namespace clang
diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt
index 3cb3cb8d3c80..3a9f34f3d275 100644
--- a/unittests/Basic/CMakeLists.txt
+++ b/unittests/Basic/CMakeLists.txt
@@ -6,6 +6,7 @@ add_clang_unittest(BasicTests
CharInfoTest.cpp
DiagnosticTest.cpp
FileManagerTest.cpp
+ MemoryBufferCacheTest.cpp
SourceManagerTest.cpp
VirtualFileSystemTest.cpp
)
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index 4cf21cd8459a..a19535e1047c 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -12,6 +12,7 @@
#include "clang/Basic/FileSystemStatCache.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -29,6 +30,12 @@ private:
llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls;
void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
+#ifndef LLVM_ON_WIN32
+ SmallString<128> NormalizedPath(Path);
+ llvm::sys::path::native(NormalizedPath);
+ Path = NormalizedPath.c_str();
+#endif
+
FileData Data;
Data.Name = Path;
Data.Size = 0;
@@ -55,6 +62,12 @@ public:
LookupResult getStat(StringRef Path, FileData &Data, bool isFile,
std::unique_ptr<vfs::File> *F,
vfs::FileSystem &FS) override {
+#ifndef LLVM_ON_WIN32
+ SmallString<128> NormalizedPath(Path);
+ llvm::sys::path::native(NormalizedPath);
+ Path = NormalizedPath.c_str();
+#endif
+
if (StatCalls.count(Path) != 0) {
Data = StatCalls[Path];
return CacheExists;
@@ -140,6 +153,7 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
const FileEntry *file = manager.getFile("/tmp/test");
ASSERT_TRUE(file != nullptr);
+ ASSERT_TRUE(file->isValid());
EXPECT_EQ("/tmp/test", file->getName());
const DirectoryEntry *dir = file->getDir();
@@ -164,6 +178,7 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
const FileEntry *file = manager.getFile("virtual/dir/bar.h");
ASSERT_TRUE(file != nullptr);
+ ASSERT_TRUE(file->isValid());
EXPECT_EQ("virtual/dir/bar.h", file->getName());
const DirectoryEntry *dir = file->getDir();
@@ -185,7 +200,9 @@ TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
const FileEntry *fileFoo = manager.getFile("foo.cpp");
const FileEntry *fileBar = manager.getFile("bar.cpp");
ASSERT_TRUE(fileFoo != nullptr);
+ ASSERT_TRUE(fileFoo->isValid());
ASSERT_TRUE(fileBar != nullptr);
+ ASSERT_TRUE(fileBar->isValid());
EXPECT_NE(fileFoo, fileBar);
}
@@ -231,8 +248,8 @@ TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
statCache->InjectFile("abc/bar.cpp", 42);
manager.addStatCache(std::move(statCache));
- manager.getVirtualFile("abc/foo.cpp", 100, 0);
- manager.getVirtualFile("abc/bar.cpp", 200, 0);
+ ASSERT_TRUE(manager.getVirtualFile("abc/foo.cpp", 100, 0)->isValid());
+ ASSERT_TRUE(manager.getVirtualFile("abc/bar.cpp", 200, 0)->isValid());
EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
}
@@ -246,6 +263,37 @@ TEST_F(FileManagerTest, addRemoveStatCache) {
manager.removeStatCache(statCache);
}
+// getFile() Should return the same entry as getVirtualFile if the file actually
+// is a virtual file, even if the name is not exactly the same (but is after
+// normalisation done by the file system, like on Windows). This can be checked
+// here by checkng the size.
+TEST_F(FileManagerTest, getVirtualFileWithDifferentName) {
+ // Inject fake files into the file system.
+ auto statCache = llvm::make_unique<FakeStatCache>();
+ statCache->InjectDirectory("c:\\tmp", 42);
+ statCache->InjectFile("c:\\tmp\\test", 43);
+
+ manager.addStatCache(std::move(statCache));
+
+ // Inject the virtual file:
+ const FileEntry *file1 = manager.getVirtualFile("c:\\tmp\\test", 123, 1);
+ ASSERT_TRUE(file1 != nullptr);
+ ASSERT_TRUE(file1->isValid());
+ EXPECT_EQ(43U, file1->getUniqueID().getFile());
+ EXPECT_EQ(123, file1->getSize());
+
+ // Lookup the virtual file with a different name:
+ const FileEntry *file2 = manager.getFile("c:/tmp/test", 100, 1);
+ ASSERT_TRUE(file2 != nullptr);
+ ASSERT_TRUE(file2->isValid());
+ // Check that it's the same UFE:
+ EXPECT_EQ(file1, file2);
+ EXPECT_EQ(43U, file2->getUniqueID().getFile());
+ // Check that the contents of the UFE are not overwritten by the entry in the
+ // filesystem:
+ EXPECT_EQ(123, file2->getSize());
+}
+
#endif // !LLVM_ON_WIN32
} // anonymous namespace
diff --git a/unittests/Basic/MemoryBufferCacheTest.cpp b/unittests/Basic/MemoryBufferCacheTest.cpp
new file mode 100644
index 000000000000..99178f8150cc
--- /dev/null
+++ b/unittests/Basic/MemoryBufferCacheTest.cpp
@@ -0,0 +1,94 @@
+//===- MemoryBufferCacheTest.cpp - MemoryBufferCache tests ----------------===//
+//
+// 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"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+std::unique_ptr<MemoryBuffer> getBuffer(int I) {
+ SmallVector<char, 8> Bytes;
+ raw_svector_ostream(Bytes) << "data:" << I;
+ return MemoryBuffer::getMemBuffer(StringRef(Bytes.data(), Bytes.size()), "",
+ /* RequiresNullTerminator = */ false);
+}
+
+TEST(MemoryBufferCacheTest, addBuffer) {
+ auto B1 = getBuffer(1);
+ auto B2 = getBuffer(2);
+ auto B3 = getBuffer(3);
+ auto *RawB1 = B1.get();
+ auto *RawB2 = B2.get();
+ auto *RawB3 = B3.get();
+
+ // Add a few buffers.
+ MemoryBufferCache Cache;
+ EXPECT_EQ(RawB1, &Cache.addBuffer("1", std::move(B1)));
+ EXPECT_EQ(RawB2, &Cache.addBuffer("2", std::move(B2)));
+ EXPECT_EQ(RawB3, &Cache.addBuffer("3", std::move(B3)));
+ EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
+ EXPECT_EQ(RawB2, Cache.lookupBuffer("2"));
+ EXPECT_EQ(RawB3, Cache.lookupBuffer("3"));
+ EXPECT_FALSE(Cache.isBufferFinal("1"));
+ EXPECT_FALSE(Cache.isBufferFinal("2"));
+ EXPECT_FALSE(Cache.isBufferFinal("3"));
+
+ // Remove the middle buffer.
+ EXPECT_FALSE(Cache.tryToRemoveBuffer("2"));
+ EXPECT_EQ(nullptr, Cache.lookupBuffer("2"));
+ EXPECT_FALSE(Cache.isBufferFinal("2"));
+
+ // Replace the middle buffer.
+ B2 = getBuffer(2);
+ RawB2 = B2.get();
+ EXPECT_EQ(RawB2, &Cache.addBuffer("2", std::move(B2)));
+
+ // Check that nothing is final.
+ EXPECT_FALSE(Cache.isBufferFinal("1"));
+ EXPECT_FALSE(Cache.isBufferFinal("2"));
+ EXPECT_FALSE(Cache.isBufferFinal("3"));
+}
+
+TEST(MemoryBufferCacheTest, finalizeCurrentBuffers) {
+ // Add a buffer.
+ MemoryBufferCache Cache;
+ auto B1 = getBuffer(1);
+ auto *RawB1 = B1.get();
+ Cache.addBuffer("1", std::move(B1));
+ ASSERT_FALSE(Cache.isBufferFinal("1"));
+
+ // Finalize it.
+ Cache.finalizeCurrentBuffers();
+ EXPECT_TRUE(Cache.isBufferFinal("1"));
+ EXPECT_TRUE(Cache.tryToRemoveBuffer("1"));
+ EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
+ EXPECT_TRUE(Cache.isBufferFinal("1"));
+
+ // Repeat.
+ auto B2 = getBuffer(2);
+ auto *RawB2 = B2.get();
+ Cache.addBuffer("2", std::move(B2));
+ EXPECT_FALSE(Cache.isBufferFinal("2"));
+
+ Cache.finalizeCurrentBuffers();
+ EXPECT_TRUE(Cache.isBufferFinal("1"));
+ EXPECT_TRUE(Cache.isBufferFinal("2"));
+ EXPECT_TRUE(Cache.tryToRemoveBuffer("1"));
+ EXPECT_TRUE(Cache.tryToRemoveBuffer("2"));
+ EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
+ EXPECT_EQ(RawB2, Cache.lookupBuffer("2"));
+ EXPECT_TRUE(Cache.isBufferFinal("1"));
+ EXPECT_TRUE(Cache.isBufferFinal("2"));
+}
+
+} // namespace
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index a967b0ec7c21..dddc3f98662d 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -12,6 +12,7 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
@@ -78,10 +79,11 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
SourceMgr.setMainFileID(mainFileID);
VoidModuleLoader ModLoader;
+ MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, HeaderInfo, ModLoader,
+ SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
@@ -198,10 +200,11 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
VoidModuleLoader ModLoader;
+ MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, HeaderInfo, ModLoader,
+ SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
@@ -298,10 +301,11 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
VoidModuleLoader ModLoader;
+ MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, HeaderInfo, ModLoader,
+ SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
index 580343d93ea1..0856b17791fa 100644
--- a/unittests/Basic/VirtualFileSystemTest.cpp
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -305,6 +305,22 @@ struct ScopedDir {
}
operator StringRef() { return Path.str(); }
};
+
+struct ScopedLink {
+ SmallString<128> Path;
+ ScopedLink(const Twine &To, const Twine &From) {
+ Path = From.str();
+ std::error_code EC = sys::fs::create_link(To, From);
+ if (EC)
+ Path = "";
+ EXPECT_FALSE(EC);
+ }
+ ~ScopedLink() {
+ if (Path != "")
+ EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
+ }
+ operator StringRef() { return Path.str(); }
+};
} // end anonymous namespace
TEST(VirtualFileSystemTest, BasicRealFSIteration) {
@@ -334,6 +350,42 @@ TEST(VirtualFileSystemTest, BasicRealFSIteration) {
EXPECT_EQ(vfs::directory_iterator(), I);
}
+#ifdef LLVM_ON_UNIX
+TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
+
+ ScopedLink _a("no_such_file", TestDirectory + "/a");
+ ScopedDir _b(TestDirectory + "/b");
+ ScopedLink _c("no_such_file", TestDirectory + "/c");
+
+ std::error_code EC;
+ for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
+ I != E; I.increment(EC)) {
+ // Skip broken symlinks.
+ auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
+ if (EC == EC2) {
+ EC.clear();
+ continue;
+ }
+ // For bot debugging.
+ if (EC) {
+ outs() << "Error code found:\n"
+ << "EC value: " << EC.value() << "\n"
+ << "EC category: " << EC.category().name()
+ << "EC message: " << EC.message() << "\n";
+
+ outs() << "Error code tested for:\n"
+ << "EC value: " << EC2.value() << "\n"
+ << "EC category: " << EC2.category().name()
+ << "EC message: " << EC2.message() << "\n";
+ }
+ ASSERT_FALSE(EC);
+ EXPECT_TRUE(I->getName() == _b);
+ }
+}
+#endif
+
TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
@@ -373,6 +425,56 @@ TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
EXPECT_EQ(1, Counts[3]); // d
}
+#ifdef LLVM_ON_UNIX
+TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
+
+ ScopedLink _a("no_such_file", TestDirectory + "/a");
+ ScopedDir _b(TestDirectory + "/b");
+ ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
+ ScopedDir _bb(TestDirectory + "/b/b");
+ ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
+ ScopedLink _c("no_such_file", TestDirectory + "/c");
+ ScopedDir _d(TestDirectory + "/d");
+ ScopedDir _dd(TestDirectory + "/d/d");
+ ScopedDir _ddd(TestDirectory + "/d/d/d");
+ ScopedLink _e("no_such_file", TestDirectory + "/e");
+ std::vector<StringRef> Expected = {_b, _bb, _d, _dd, _ddd};
+
+ std::vector<std::string> Contents;
+ std::error_code EC;
+ for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
+ I != E; I.increment(EC)) {
+ // Skip broken symlinks.
+ auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
+ if (EC == EC2) {
+ EC.clear();
+ continue;
+ }
+ // For bot debugging.
+ if (EC) {
+ outs() << "Error code found:\n"
+ << "EC value: " << EC.value() << "\n"
+ << "EC category: " << EC.category().name()
+ << "EC message: " << EC.message() << "\n";
+
+ outs() << "Error code tested for:\n"
+ << "EC value: " << EC2.value() << "\n"
+ << "EC category: " << EC2.category().name()
+ << "EC message: " << EC2.message() << "\n";
+ }
+ ASSERT_FALSE(EC);
+ Contents.push_back(I->getName());
+ }
+
+ // Check sorted contents.
+ std::sort(Contents.begin(), Contents.end());
+ EXPECT_EQ(Expected.size(), Contents.size());
+ EXPECT_TRUE(std::equal(Contents.begin(), Contents.end(), Expected.begin()));
+}
+#endif
+
template <typename DirIter>
static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
std::error_code EC;
diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt
index b9c52f7a53f9..a4f75d26f660 100644
--- a/unittests/Driver/CMakeLists.txt
+++ b/unittests/Driver/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
Support
+ Option
)
add_clang_unittest(ClangDriverTests
diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt
index eb7756a0ba56..507d643ba102 100644
--- a/unittests/Format/CMakeLists.txt
+++ b/unittests/Format/CMakeLists.txt
@@ -5,11 +5,13 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(FormatTests
CleanupTest.cpp
FormatTest.cpp
- FormatTestJava.cpp
+ FormatTestComments.cpp
FormatTestJS.cpp
+ FormatTestJava.cpp
FormatTestObjC.cpp
FormatTestProto.cpp
FormatTestSelective.cpp
+ NamespaceEndCommentsFixerTest.cpp
SortImportsTestJS.cpp
SortIncludesTest.cpp
)
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index b402b5c4a54c..e6ba2230ac6d 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -71,6 +71,13 @@ protected:
void verifyFormat(llvm::StringRef Code,
const FormatStyle &Style = getLLVMStyle()) {
EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
+ if (Style.Language == FormatStyle::LK_Cpp) {
+ // Objective-C++ is a superset of C++, so everything checked for C++
+ // needs to be checked for Objective-C++ as well.
+ FormatStyle ObjCStyle = Style;
+ ObjCStyle.Language = FormatStyle::LK_ObjC;
+ EXPECT_EQ(Code.str(), format(test::messUp(Code), ObjCStyle));
+ }
}
void verifyIncompleteFormat(llvm::StringRef Code,
@@ -139,6 +146,8 @@ TEST_F(FormatTest, NestedNameSpecifiers) {
verifyFormat("::ns::SomeFunction(::ns::SomeOtherFunction())");
verifyFormat("static constexpr bool Bar = decltype(bar())::value;");
verifyFormat("bool a = 2 < ::SomeFunction();");
+ verifyFormat("ALWAYS_INLINE ::std::string getName();");
+ verifyFormat("some::string getName();");
}
TEST_F(FormatTest, OnlyGeneratesNecessaryReplacements) {
@@ -261,6 +270,15 @@ TEST_F(FormatTest, RemovesEmptyLines) {
"}"));
// FIXME: This is slightly inconsistent.
+ FormatStyle LLVMWithNoNamespaceFix = getLLVMStyle();
+ LLVMWithNoNamespaceFix.FixNamespaceComments = false;
+ EXPECT_EQ("namespace {\n"
+ "int i;\n"
+ "}",
+ format("namespace {\n"
+ "int i;\n"
+ "\n"
+ "}", LLVMWithNoNamespaceFix));
EXPECT_EQ("namespace {\n"
"int i;\n"
"}",
@@ -866,1061 +884,6 @@ TEST_F(FormatTest, FormatsLabels) {
}
//===----------------------------------------------------------------------===//
-// Tests for comments.
-//===----------------------------------------------------------------------===//
-
-TEST_F(FormatTest, UnderstandsSingleLineComments) {
- verifyFormat("//* */");
- verifyFormat("// line 1\n"
- "// line 2\n"
- "void f() {}\n");
-
- verifyFormat("void f() {\n"
- " // Doesn't do anything\n"
- "}");
- verifyFormat("SomeObject\n"
- " // Calling someFunction on SomeObject\n"
- " .someFunction();");
- verifyFormat("auto result = SomeObject\n"
- " // Calling someFunction on SomeObject\n"
- " .someFunction();");
- verifyFormat("void f(int i, // some comment (probably for i)\n"
- " int j, // some comment (probably for j)\n"
- " int k); // some comment (probably for k)");
- verifyFormat("void f(int i,\n"
- " // some comment (probably for j)\n"
- " int j,\n"
- " // some comment (probably for k)\n"
- " int k);");
-
- verifyFormat("int i // This is a fancy variable\n"
- " = 5; // with nicely aligned comment.");
-
- verifyFormat("// Leading comment.\n"
- "int a; // Trailing comment.");
- verifyFormat("int a; // Trailing comment\n"
- " // on 2\n"
- " // or 3 lines.\n"
- "int b;");
- verifyFormat("int a; // Trailing comment\n"
- "\n"
- "// Leading comment.\n"
- "int b;");
- verifyFormat("int a; // Comment.\n"
- " // More details.\n"
- "int bbbb; // Another comment.");
- verifyFormat(
- "int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; // comment\n"
- "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; // comment\n"
- "int cccccccccccccccccccccccccccccc; // comment\n"
- "int ddd; // looooooooooooooooooooooooong comment\n"
- "int aaaaaaaaaaaaaaaaaaaaaaa; // comment\n"
- "int bbbbbbbbbbbbbbbbbbbbb; // comment\n"
- "int ccccccccccccccccccc; // comment");
-
- verifyFormat("#include \"a\" // comment\n"
- "#include \"a/b/c\" // comment");
- verifyFormat("#include <a> // comment\n"
- "#include <a/b/c> // comment");
- EXPECT_EQ("#include \"a\" // comment\n"
- "#include \"a/b/c\" // comment",
- format("#include \\\n"
- " \"a\" // comment\n"
- "#include \"a/b/c\" // comment"));
-
- verifyFormat("enum E {\n"
- " // comment\n"
- " VAL_A, // comment\n"
- " VAL_B\n"
- "};");
-
- verifyFormat(
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; // Trailing comment");
- verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
- " // Comment inside a statement.\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
- verifyFormat("SomeFunction(a,\n"
- " // comment\n"
- " b + x);");
- verifyFormat("SomeFunction(a, a,\n"
- " // comment\n"
- " b + x);");
- verifyFormat(
- "bool aaaaaaaaaaaaa = // comment\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
-
- verifyFormat("int aaaa; // aaaaa\n"
- "int aa; // aaaaaaa",
- getLLVMStyleWithColumns(20));
-
- EXPECT_EQ("void f() { // This does something ..\n"
- "}\n"
- "int a; // This is unrelated",
- format("void f() { // This does something ..\n"
- " }\n"
- "int a; // This is unrelated"));
- EXPECT_EQ("class C {\n"
- " void f() { // This does something ..\n"
- " } // awesome..\n"
- "\n"
- " int a; // This is unrelated\n"
- "};",
- format("class C{void f() { // This does something ..\n"
- " } // awesome..\n"
- " \n"
- "int a; // This is unrelated\n"
- "};"));
-
- EXPECT_EQ("int i; // single line trailing comment",
- format("int i;\\\n// single line trailing comment"));
-
- verifyGoogleFormat("int a; // Trailing comment.");
-
- verifyFormat("someFunction(anotherFunction( // Force break.\n"
- " parameter));");
-
- verifyGoogleFormat("#endif // HEADER_GUARD");
-
- verifyFormat("const char *test[] = {\n"
- " // A\n"
- " \"aaaa\",\n"
- " // B\n"
- " \"aaaaa\"};");
- verifyGoogleFormat(
- "aaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaaaaaa); // 81_cols_with_this_comment");
- EXPECT_EQ("D(a, {\n"
- " // test\n"
- " int a;\n"
- "});",
- format("D(a, {\n"
- "// test\n"
- "int a;\n"
- "});"));
-
- EXPECT_EQ("lineWith(); // comment\n"
- "// at start\n"
- "otherLine();",
- format("lineWith(); // comment\n"
- "// at start\n"
- "otherLine();"));
- EXPECT_EQ("lineWith(); // comment\n"
- "/*\n"
- " * at start */\n"
- "otherLine();",
- format("lineWith(); // comment\n"
- "/*\n"
- " * at start */\n"
- "otherLine();"));
- EXPECT_EQ("lineWith(); // comment\n"
- " // at start\n"
- "otherLine();",
- format("lineWith(); // comment\n"
- " // at start\n"
- "otherLine();"));
-
- EXPECT_EQ("lineWith(); // comment\n"
- "// at start\n"
- "otherLine(); // comment",
- format("lineWith(); // comment\n"
- "// at start\n"
- "otherLine(); // comment"));
- EXPECT_EQ("lineWith();\n"
- "// at start\n"
- "otherLine(); // comment",
- format("lineWith();\n"
- " // at start\n"
- "otherLine(); // comment"));
- EXPECT_EQ("// first\n"
- "// at start\n"
- "otherLine(); // comment",
- format("// first\n"
- " // at start\n"
- "otherLine(); // comment"));
- EXPECT_EQ("f();\n"
- "// first\n"
- "// at start\n"
- "otherLine(); // comment",
- format("f();\n"
- "// first\n"
- " // at start\n"
- "otherLine(); // comment"));
- verifyFormat("f(); // comment\n"
- "// first\n"
- "// at start\n"
- "otherLine();");
- EXPECT_EQ("f(); // comment\n"
- "// first\n"
- "// at start\n"
- "otherLine();",
- format("f(); // comment\n"
- "// first\n"
- " // at start\n"
- "otherLine();"));
- EXPECT_EQ("f(); // comment\n"
- " // first\n"
- "// at start\n"
- "otherLine();",
- format("f(); // comment\n"
- " // first\n"
- "// at start\n"
- "otherLine();"));
- EXPECT_EQ("void f() {\n"
- " lineWith(); // comment\n"
- " // at start\n"
- "}",
- format("void f() {\n"
- " lineWith(); // comment\n"
- " // at start\n"
- "}"));
- EXPECT_EQ("int xy; // a\n"
- "int z; // b",
- format("int xy; // a\n"
- "int z; //b"));
- EXPECT_EQ("int xy; // a\n"
- "int z; // bb",
- format("int xy; // a\n"
- "int z; //bb",
- getLLVMStyleWithColumns(12)));
-
- verifyFormat("#define A \\\n"
- " int i; /* iiiiiiiiiiiiiiiiiiiii */ \\\n"
- " int jjjjjjjjjjjjjjjjjjjjjjjj; /* */",
- getLLVMStyleWithColumns(60));
- verifyFormat(
- "#define A \\\n"
- " int i; /* iiiiiiiiiiiiiiiiiiiii */ \\\n"
- " int jjjjjjjjjjjjjjjjjjjjjjjj; /* */",
- getLLVMStyleWithColumns(61));
-
- verifyFormat("if ( // This is some comment\n"
- " x + 3) {\n"
- "}");
- EXPECT_EQ("if ( // This is some comment\n"
- " // spanning two lines\n"
- " x + 3) {\n"
- "}",
- format("if( // This is some comment\n"
- " // spanning two lines\n"
- " x + 3) {\n"
- "}"));
-
- verifyNoCrash("/\\\n/");
- verifyNoCrash("/\\\n* */");
- // The 0-character somehow makes the lexer return a proper comment.
- verifyNoCrash(StringRef("/*\\\0\n/", 6));
-}
-
-TEST_F(FormatTest, KeepsParameterWithTrailingCommentsOnTheirOwnLine) {
- EXPECT_EQ("SomeFunction(a,\n"
- " b, // comment\n"
- " c);",
- format("SomeFunction(a,\n"
- " b, // comment\n"
- " c);"));
- EXPECT_EQ("SomeFunction(a, b,\n"
- " // comment\n"
- " c);",
- format("SomeFunction(a,\n"
- " b,\n"
- " // comment\n"
- " c);"));
- EXPECT_EQ("SomeFunction(a, b, // comment (unclear relation)\n"
- " c);",
- format("SomeFunction(a, b, // comment (unclear relation)\n"
- " c);"));
- EXPECT_EQ("SomeFunction(a, // comment\n"
- " b,\n"
- " c); // comment",
- format("SomeFunction(a, // comment\n"
- " b,\n"
- " c); // comment"));
- EXPECT_EQ("aaaaaaaaaa(aaaa(aaaa,\n"
- " aaaa), //\n"
- " aaaa, bbbbb);",
- format("aaaaaaaaaa(aaaa(aaaa,\n"
- "aaaa), //\n"
- "aaaa, bbbbb);"));
-}
-
-TEST_F(FormatTest, RemovesTrailingWhitespaceOfComments) {
- EXPECT_EQ("// comment", format("// comment "));
- EXPECT_EQ("int aaaaaaa, bbbbbbb; // comment",
- format("int aaaaaaa, bbbbbbb; // comment ",
- getLLVMStyleWithColumns(33)));
- EXPECT_EQ("// comment\\\n", format("// comment\\\n \t \v \f "));
- EXPECT_EQ("// comment \\\n", format("// comment \\\n \t \v \f "));
-}
-
-TEST_F(FormatTest, UnderstandsBlockComments) {
- verifyFormat("f(/*noSpaceAfterParameterNamingComment=*/true);");
- verifyFormat("void f() { g(/*aaa=*/x, /*bbb=*/!y, /*c=*/::c); }");
- EXPECT_EQ("f(aaaaaaaaaaaaaaaaaaaaaaaaa, /* Trailing comment for aa... */\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbb);",
- format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , \\\n"
- "/* Trailing comment for aa... */\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbb);"));
- EXPECT_EQ(
- "f(aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " /* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);",
- format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , \n"
- "/* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);"));
- EXPECT_EQ(
- "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaa) { /*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/\n"
- "}",
- format("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaa ,\n"
- " aaaaaaaaaaaaaaaaaa) { /*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/\n"
- "}"));
- verifyFormat("f(/* aaaaaaaaaaaaaaaaaa = */\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
-
- FormatStyle NoBinPacking = getLLVMStyle();
- NoBinPacking.BinPackParameters = false;
- verifyFormat("aaaaaaaa(/* parameter 1 */ aaaaaa,\n"
- " /* parameter 2 */ aaaaaa,\n"
- " /* parameter 3 */ aaaaaa,\n"
- " /* parameter 4 */ aaaaaa);",
- NoBinPacking);
-
- // Aligning block comments in macros.
- verifyGoogleFormat("#define A \\\n"
- " int i; /*a*/ \\\n"
- " int jjj; /*b*/");
-}
-
-TEST_F(FormatTest, AlignsBlockComments) {
- EXPECT_EQ("/*\n"
- " * Really multi-line\n"
- " * comment.\n"
- " */\n"
- "void f() {}",
- format(" /*\n"
- " * Really multi-line\n"
- " * comment.\n"
- " */\n"
- " void f() {}"));
- EXPECT_EQ("class C {\n"
- " /*\n"
- " * Another multi-line\n"
- " * comment.\n"
- " */\n"
- " void f() {}\n"
- "};",
- format("class C {\n"
- "/*\n"
- " * Another multi-line\n"
- " * comment.\n"
- " */\n"
- "void f() {}\n"
- "};"));
- EXPECT_EQ("/*\n"
- " 1. This is a comment with non-trivial formatting.\n"
- " 1.1. We have to indent/outdent all lines equally\n"
- " 1.1.1. to keep the formatting.\n"
- " */",
- format(" /*\n"
- " 1. This is a comment with non-trivial formatting.\n"
- " 1.1. We have to indent/outdent all lines equally\n"
- " 1.1.1. to keep the formatting.\n"
- " */"));
- EXPECT_EQ("/*\n"
- "Don't try to outdent if there's not enough indentation.\n"
- "*/",
- format(" /*\n"
- " Don't try to outdent if there's not enough indentation.\n"
- " */"));
-
- EXPECT_EQ("int i; /* Comment with empty...\n"
- " *\n"
- " * line. */",
- format("int i; /* Comment with empty...\n"
- " *\n"
- " * line. */"));
- EXPECT_EQ("int foobar = 0; /* comment */\n"
- "int bar = 0; /* multiline\n"
- " comment 1 */\n"
- "int baz = 0; /* multiline\n"
- " comment 2 */\n"
- "int bzz = 0; /* multiline\n"
- " comment 3 */",
- format("int foobar = 0; /* comment */\n"
- "int bar = 0; /* multiline\n"
- " comment 1 */\n"
- "int baz = 0; /* multiline\n"
- " comment 2 */\n"
- "int bzz = 0; /* multiline\n"
- " comment 3 */"));
- EXPECT_EQ("int foobar = 0; /* comment */\n"
- "int bar = 0; /* multiline\n"
- " comment */\n"
- "int baz = 0; /* multiline\n"
- "comment */",
- format("int foobar = 0; /* comment */\n"
- "int bar = 0; /* multiline\n"
- "comment */\n"
- "int baz = 0; /* multiline\n"
- "comment */"));
-}
-
-TEST_F(FormatTest, CommentReflowingCanBeTurnedOff) {
- FormatStyle Style = getLLVMStyleWithColumns(20);
- Style.ReflowComments = false;
- verifyFormat("// aaaaaaaaa aaaaaaaaaa aaaaaaaaaa", Style);
- verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa */", Style);
-}
-
-TEST_F(FormatTest, CorrectlyHandlesLengthOfBlockComments) {
- EXPECT_EQ("double *x; /* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */",
- format("double *x; /* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */"));
- EXPECT_EQ(
- "void ffffffffffff(\n"
- " int aaaaaaaa, int bbbbbbbb,\n"
- " int cccccccccccc) { /*\n"
- " aaaaaaaaaa\n"
- " aaaaaaaaaaaaa\n"
- " bbbbbbbbbbbbbb\n"
- " bbbbbbbbbb\n"
- " */\n"
- "}",
- format("void ffffffffffff(int aaaaaaaa, int bbbbbbbb, int cccccccccccc)\n"
- "{ /*\n"
- " aaaaaaaaaa aaaaaaaaaaaaa\n"
- " bbbbbbbbbbbbbb bbbbbbbbbb\n"
- " */\n"
- "}",
- getLLVMStyleWithColumns(40)));
-}
-
-TEST_F(FormatTest, DontBreakNonTrailingBlockComments) {
- EXPECT_EQ("void ffffffffff(\n"
- " int aaaaa /* test */);",
- format("void ffffffffff(int aaaaa /* test */);",
- getLLVMStyleWithColumns(35)));
-}
-
-TEST_F(FormatTest, SplitsLongCxxComments) {
- EXPECT_EQ("// A comment that\n"
- "// doesn't fit on\n"
- "// one line",
- format("// A comment that doesn't fit on one line",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("/// A comment that\n"
- "/// doesn't fit on\n"
- "/// one line",
- format("/// A comment that doesn't fit on one line",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("//! A comment that\n"
- "//! doesn't fit on\n"
- "//! one line",
- format("//! A comment that doesn't fit on one line",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("// a b c d\n"
- "// e f g\n"
- "// h i j k",
- format("// a b c d e f g h i j k", getLLVMStyleWithColumns(10)));
- EXPECT_EQ(
- "// a b c d\n"
- "// e f g\n"
- "// h i j k",
- format("\\\n// a b c d e f g h i j k", getLLVMStyleWithColumns(10)));
- EXPECT_EQ("if (true) // A comment that\n"
- " // doesn't fit on\n"
- " // one line",
- format("if (true) // A comment that doesn't fit on one line ",
- getLLVMStyleWithColumns(30)));
- EXPECT_EQ("// Don't_touch_leading_whitespace",
- format("// Don't_touch_leading_whitespace",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("// Add leading\n"
- "// whitespace",
- format("//Add leading whitespace", getLLVMStyleWithColumns(20)));
- EXPECT_EQ("/// Add leading\n"
- "/// whitespace",
- format("///Add leading whitespace", getLLVMStyleWithColumns(20)));
- EXPECT_EQ("//! Add leading\n"
- "//! whitespace",
- format("//!Add leading whitespace", getLLVMStyleWithColumns(20)));
- EXPECT_EQ("// whitespace", format("//whitespace", getLLVMStyle()));
- EXPECT_EQ("// Even if it makes the line exceed the column\n"
- "// limit",
- format("//Even if it makes the line exceed the column limit",
- getLLVMStyleWithColumns(51)));
- EXPECT_EQ("//--But not here", format("//--But not here", getLLVMStyle()));
-
- EXPECT_EQ("// aa bb cc dd",
- format("// aa bb cc dd ",
- getLLVMStyleWithColumns(15)));
-
- EXPECT_EQ("// A comment before\n"
- "// a macro\n"
- "// definition\n"
- "#define a b",
- format("// A comment before a macro definition\n"
- "#define a b",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("void ffffff(\n"
- " int aaaaaaaaa, // wwww\n"
- " int bbbbbbbbbb, // xxxxxxx\n"
- " // yyyyyyyyyy\n"
- " int c, int d, int e) {}",
- format("void ffffff(\n"
- " int aaaaaaaaa, // wwww\n"
- " int bbbbbbbbbb, // xxxxxxx yyyyyyyyyy\n"
- " int c, int d, int e) {}",
- getLLVMStyleWithColumns(40)));
- EXPECT_EQ("//\t aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- format("//\t aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ(
- "#define XXX // a b c d\n"
- " // e f g h",
- format("#define XXX // a b c d e f g h", getLLVMStyleWithColumns(22)));
- EXPECT_EQ(
- "#define XXX // q w e r\n"
- " // t y u i",
- format("#define XXX //q w e r t y u i", getLLVMStyleWithColumns(22)));
-}
-
-TEST_F(FormatTest, PreservesHangingIndentInCxxComments) {
- EXPECT_EQ("// A comment\n"
- "// that doesn't\n"
- "// fit on one\n"
- "// line",
- format("// A comment that doesn't fit on one line",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("/// A comment\n"
- "/// that doesn't\n"
- "/// fit on one\n"
- "/// line",
- format("/// A comment that doesn't fit on one line",
- getLLVMStyleWithColumns(20)));
-}
-
-TEST_F(FormatTest, DontSplitLineCommentsWithEscapedNewlines) {
- EXPECT_EQ("// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
- "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
- "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- format("// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
- "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
- "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
- EXPECT_EQ("int a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
- " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
- " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
- format("int a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
- " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
- " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
- getLLVMStyleWithColumns(50)));
- // FIXME: One day we might want to implement adjustment of leading whitespace
- // of the consecutive lines in this kind of comment:
- EXPECT_EQ("double\n"
- " a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
- " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
- " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
- format("double a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
- " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
- " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
- getLLVMStyleWithColumns(49)));
-}
-
-TEST_F(FormatTest, DontSplitLineCommentsWithPragmas) {
- FormatStyle Pragmas = getLLVMStyleWithColumns(30);
- Pragmas.CommentPragmas = "^ IWYU pragma:";
- EXPECT_EQ(
- "// IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb",
- format("// IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb", Pragmas));
- EXPECT_EQ(
- "/* IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb */",
- format("/* IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb */", Pragmas));
-}
-
-TEST_F(FormatTest, PriorityOfCommentBreaking) {
- EXPECT_EQ("if (xxx ==\n"
- " yyy && // aaaaaaaaaaaa bbbbbbbbb\n"
- " zzz)\n"
- " q();",
- format("if (xxx == yyy && // aaaaaaaaaaaa bbbbbbbbb\n"
- " zzz) q();",
- getLLVMStyleWithColumns(40)));
- EXPECT_EQ("if (xxxxxxxxxx ==\n"
- " yyy && // aaaaaa bbbbbbbb cccc\n"
- " zzz)\n"
- " q();",
- format("if (xxxxxxxxxx == yyy && // aaaaaa bbbbbbbb cccc\n"
- " zzz) q();",
- getLLVMStyleWithColumns(40)));
- EXPECT_EQ("if (xxxxxxxxxx &&\n"
- " yyy || // aaaaaa bbbbbbbb cccc\n"
- " zzz)\n"
- " q();",
- format("if (xxxxxxxxxx && yyy || // aaaaaa bbbbbbbb cccc\n"
- " zzz) q();",
- getLLVMStyleWithColumns(40)));
- EXPECT_EQ("fffffffff(\n"
- " &xxx, // aaaaaaaaaaaa bbbbbbbbbbb\n"
- " zzz);",
- format("fffffffff(&xxx, // aaaaaaaaaaaa bbbbbbbbbbb\n"
- " zzz);",
- getLLVMStyleWithColumns(40)));
-}
-
-TEST_F(FormatTest, MultiLineCommentsInDefines) {
- EXPECT_EQ("#define A(x) /* \\\n"
- " a comment \\\n"
- " inside */ \\\n"
- " f();",
- format("#define A(x) /* \\\n"
- " a comment \\\n"
- " inside */ \\\n"
- " f();",
- getLLVMStyleWithColumns(17)));
- EXPECT_EQ("#define A( \\\n"
- " x) /* \\\n"
- " a comment \\\n"
- " inside */ \\\n"
- " f();",
- format("#define A( \\\n"
- " x) /* \\\n"
- " a comment \\\n"
- " inside */ \\\n"
- " f();",
- getLLVMStyleWithColumns(17)));
-}
-
-TEST_F(FormatTest, ParsesCommentsAdjacentToPPDirectives) {
- EXPECT_EQ("namespace {}\n// Test\n#define A",
- format("namespace {}\n // Test\n#define A"));
- EXPECT_EQ("namespace {}\n/* Test */\n#define A",
- format("namespace {}\n /* Test */\n#define A"));
- EXPECT_EQ("namespace {}\n/* Test */ #define A",
- format("namespace {}\n /* Test */ #define A"));
-}
-
-TEST_F(FormatTest, SplitsLongLinesInComments) {
- EXPECT_EQ("/* This is a long\n"
- " * comment that\n"
- " * doesn't\n"
- " * fit on one line.\n"
- " */",
- format("/* "
- "This is a long "
- "comment that "
- "doesn't "
- "fit on one line. */",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ(
- "/* a b c d\n"
- " * e f g\n"
- " * h i j k\n"
- " */",
- format("/* a b c d e f g h i j k */", getLLVMStyleWithColumns(10)));
- EXPECT_EQ(
- "/* a b c d\n"
- " * e f g\n"
- " * h i j k\n"
- " */",
- format("\\\n/* a b c d e f g h i j k */", getLLVMStyleWithColumns(10)));
- EXPECT_EQ("/*\n"
- "This is a long\n"
- "comment that doesn't\n"
- "fit on one line.\n"
- "*/",
- format("/*\n"
- "This is a long "
- "comment that doesn't "
- "fit on one line. \n"
- "*/",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("/*\n"
- " * This is a long\n"
- " * comment that\n"
- " * doesn't fit on\n"
- " * one line.\n"
- " */",
- format("/* \n"
- " * This is a long "
- " comment that "
- " doesn't fit on "
- " one line. \n"
- " */",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("/*\n"
- " * This_is_a_comment_with_words_that_dont_fit_on_one_line\n"
- " * so_it_should_be_broken\n"
- " * wherever_a_space_occurs\n"
- " */",
- format("/*\n"
- " * This_is_a_comment_with_words_that_dont_fit_on_one_line "
- " so_it_should_be_broken "
- " wherever_a_space_occurs \n"
- " */",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("/*\n"
- " * This_comment_can_not_be_broken_into_lines\n"
- " */",
- format("/*\n"
- " * This_comment_can_not_be_broken_into_lines\n"
- " */",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("{\n"
- " /*\n"
- " This is another\n"
- " long comment that\n"
- " doesn't fit on one\n"
- " line 1234567890\n"
- " */\n"
- "}",
- format("{\n"
- "/*\n"
- "This is another "
- " long comment that "
- " doesn't fit on one"
- " line 1234567890\n"
- "*/\n"
- "}",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("{\n"
- " /*\n"
- " * This i s\n"
- " * another comment\n"
- " * t hat doesn' t\n"
- " * fit on one l i\n"
- " * n e\n"
- " */\n"
- "}",
- format("{\n"
- "/*\n"
- " * This i s"
- " another comment"
- " t hat doesn' t"
- " fit on one l i"
- " n e\n"
- " */\n"
- "}",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("/*\n"
- " * This is a long\n"
- " * comment that\n"
- " * doesn't fit on\n"
- " * one line\n"
- " */",
- format(" /*\n"
- " * This is a long comment that doesn't fit on one line\n"
- " */",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("{\n"
- " if (something) /* This is a\n"
- " long\n"
- " comment */\n"
- " ;\n"
- "}",
- format("{\n"
- " if (something) /* This is a long comment */\n"
- " ;\n"
- "}",
- getLLVMStyleWithColumns(30)));
-
- EXPECT_EQ("/* A comment before\n"
- " * a macro\n"
- " * definition */\n"
- "#define a b",
- format("/* A comment before a macro definition */\n"
- "#define a b",
- getLLVMStyleWithColumns(20)));
-
- EXPECT_EQ("/* some comment\n"
- " * a comment\n"
- "* that we break\n"
- " * another comment\n"
- "* we have to break\n"
- "* a left comment\n"
- " */",
- format(" /* some comment\n"
- " * a comment that we break\n"
- " * another comment we have to break\n"
- "* a left comment\n"
- " */",
- getLLVMStyleWithColumns(20)));
-
- EXPECT_EQ("/**\n"
- " * multiline block\n"
- " * comment\n"
- " *\n"
- " */",
- format("/**\n"
- " * multiline block comment\n"
- " *\n"
- " */",
- getLLVMStyleWithColumns(20)));
-
- EXPECT_EQ("/*\n"
- "\n"
- "\n"
- " */\n",
- format(" /* \n"
- " \n"
- " \n"
- " */\n"));
-
- EXPECT_EQ("/* a a */",
- format("/* a a */", getLLVMStyleWithColumns(15)));
- EXPECT_EQ("/* a a bc */",
- format("/* a a bc */", getLLVMStyleWithColumns(15)));
- EXPECT_EQ("/* aaa aaa\n"
- " * aaaaa */",
- format("/* aaa aaa aaaaa */", getLLVMStyleWithColumns(15)));
- EXPECT_EQ("/* aaa aaa\n"
- " * aaaaa */",
- format("/* aaa aaa aaaaa */", getLLVMStyleWithColumns(15)));
-}
-
-TEST_F(FormatTest, SplitsLongLinesInCommentsInPreprocessor) {
- EXPECT_EQ("#define X \\\n"
- " /* \\\n"
- " Test \\\n"
- " Macro comment \\\n"
- " with a long \\\n"
- " line \\\n"
- " */ \\\n"
- " A + B",
- format("#define X \\\n"
- " /*\n"
- " Test\n"
- " Macro comment with a long line\n"
- " */ \\\n"
- " A + B",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("#define X \\\n"
- " /* Macro comment \\\n"
- " with a long \\\n"
- " line */ \\\n"
- " A + B",
- format("#define X \\\n"
- " /* Macro comment with a long\n"
- " line */ \\\n"
- " A + B",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("#define X \\\n"
- " /* Macro comment \\\n"
- " * with a long \\\n"
- " * line */ \\\n"
- " A + B",
- format("#define X \\\n"
- " /* Macro comment with a long line */ \\\n"
- " A + B",
- getLLVMStyleWithColumns(20)));
-}
-
-TEST_F(FormatTest, CommentsInStaticInitializers) {
- EXPECT_EQ(
- "static SomeType type = {aaaaaaaaaaaaaaaaaaaa, /* comment */\n"
- " aaaaaaaaaaaaaaaaaaaa /* comment */,\n"
- " /* comment */ aaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaa, // comment\n"
- " aaaaaaaaaaaaaaaaaaaa};",
- format("static SomeType type = { aaaaaaaaaaaaaaaaaaaa , /* comment */\n"
- " aaaaaaaaaaaaaaaaaaaa /* comment */ ,\n"
- " /* comment */ aaaaaaaaaaaaaaaaaaaa ,\n"
- " aaaaaaaaaaaaaaaaaaaa , // comment\n"
- " aaaaaaaaaaaaaaaaaaaa };"));
- verifyFormat("static SomeType type = {aaaaaaaaaaa, // comment for aa...\n"
- " bbbbbbbbbbb, ccccccccccc};");
- verifyFormat("static SomeType type = {aaaaaaaaaaa,\n"
- " // comment for bb....\n"
- " bbbbbbbbbbb, ccccccccccc};");
- verifyGoogleFormat(
- "static SomeType type = {aaaaaaaaaaa, // comment for aa...\n"
- " bbbbbbbbbbb, ccccccccccc};");
- verifyGoogleFormat("static SomeType type = {aaaaaaaaaaa,\n"
- " // comment for bb....\n"
- " bbbbbbbbbbb, ccccccccccc};");
-
- verifyFormat("S s = {{a, b, c}, // Group #1\n"
- " {d, e, f}, // Group #2\n"
- " {g, h, i}}; // Group #3");
- verifyFormat("S s = {{// Group #1\n"
- " a, b, c},\n"
- " {// Group #2\n"
- " d, e, f},\n"
- " {// Group #3\n"
- " g, h, i}};");
-
- EXPECT_EQ("S s = {\n"
- " // Some comment\n"
- " a,\n"
- "\n"
- " // Comment after empty line\n"
- " b}",
- format("S s = {\n"
- " // Some comment\n"
- " a,\n"
- " \n"
- " // Comment after empty line\n"
- " b\n"
- "}"));
- EXPECT_EQ("S s = {\n"
- " /* Some comment */\n"
- " a,\n"
- "\n"
- " /* Comment after empty line */\n"
- " b}",
- format("S s = {\n"
- " /* Some comment */\n"
- " a,\n"
- " \n"
- " /* Comment after empty line */\n"
- " b\n"
- "}"));
- verifyFormat("const uint8_t aaaaaaaaaaaaaaaaaaaaaa[0] = {\n"
- " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
- " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
- " 0x00, 0x00, 0x00, 0x00}; // comment\n");
-}
-
-TEST_F(FormatTest, IgnoresIf0Contents) {
- EXPECT_EQ("#if 0\n"
- "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n"
- "#endif\n"
- "void f() {}",
- format("#if 0\n"
- "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n"
- "#endif\n"
- "void f( ) { }"));
- EXPECT_EQ("#if false\n"
- "void f( ) { }\n"
- "#endif\n"
- "void g() {}\n",
- format("#if false\n"
- "void f( ) { }\n"
- "#endif\n"
- "void g( ) { }\n"));
- EXPECT_EQ("enum E {\n"
- " One,\n"
- " Two,\n"
- "#if 0\n"
- "Three,\n"
- " Four,\n"
- "#endif\n"
- " Five\n"
- "};",
- format("enum E {\n"
- " One,Two,\n"
- "#if 0\n"
- "Three,\n"
- " Four,\n"
- "#endif\n"
- " Five};"));
- EXPECT_EQ("enum F {\n"
- " One,\n"
- "#if 1\n"
- " Two,\n"
- "#if 0\n"
- "Three,\n"
- " Four,\n"
- "#endif\n"
- " Five\n"
- "#endif\n"
- "};",
- format("enum F {\n"
- "One,\n"
- "#if 1\n"
- "Two,\n"
- "#if 0\n"
- "Three,\n"
- " Four,\n"
- "#endif\n"
- "Five\n"
- "#endif\n"
- "};"));
- EXPECT_EQ("enum G {\n"
- " One,\n"
- "#if 0\n"
- "Two,\n"
- "#else\n"
- " Three,\n"
- "#endif\n"
- " Four\n"
- "};",
- format("enum G {\n"
- "One,\n"
- "#if 0\n"
- "Two,\n"
- "#else\n"
- "Three,\n"
- "#endif\n"
- "Four\n"
- "};"));
- EXPECT_EQ("enum H {\n"
- " One,\n"
- "#if 0\n"
- "#ifdef Q\n"
- "Two,\n"
- "#else\n"
- "Three,\n"
- "#endif\n"
- "#endif\n"
- " Four\n"
- "};",
- format("enum H {\n"
- "One,\n"
- "#if 0\n"
- "#ifdef Q\n"
- "Two,\n"
- "#else\n"
- "Three,\n"
- "#endif\n"
- "#endif\n"
- "Four\n"
- "};"));
- EXPECT_EQ("enum I {\n"
- " One,\n"
- "#if /* test */ 0 || 1\n"
- "Two,\n"
- "Three,\n"
- "#endif\n"
- " Four\n"
- "};",
- format("enum I {\n"
- "One,\n"
- "#if /* test */ 0 || 1\n"
- "Two,\n"
- "Three,\n"
- "#endif\n"
- "Four\n"
- "};"));
- EXPECT_EQ("enum J {\n"
- " One,\n"
- "#if 0\n"
- "#if 0\n"
- "Two,\n"
- "#else\n"
- "Three,\n"
- "#endif\n"
- "Four,\n"
- "#endif\n"
- " Five\n"
- "};",
- format("enum J {\n"
- "One,\n"
- "#if 0\n"
- "#if 0\n"
- "Two,\n"
- "#else\n"
- "Three,\n"
- "#endif\n"
- "Four,\n"
- "#endif\n"
- "Five\n"
- "};"));
-}
-
-//===----------------------------------------------------------------------===//
// Tests for classes, namespaces, etc.
//===----------------------------------------------------------------------===//
@@ -2066,6 +1029,17 @@ TEST_F(FormatTest, FormatsClasses) {
verifyFormat("class ::A::B {};");
}
+TEST_F(FormatTest, BreakBeforeInheritanceComma) {
+ FormatStyle StyleWithInheritanceBreak = getLLVMStyle();
+ StyleWithInheritanceBreak.BreakBeforeInheritanceComma = true;
+
+ verifyFormat("class MyClass : public X {};", StyleWithInheritanceBreak);
+ verifyFormat("class MyClass\n"
+ " : public X\n"
+ " , public Y {};",
+ StyleWithInheritanceBreak);
+}
+
TEST_F(FormatTest, FormatsVariableDeclarationsAfterStructOrClass) {
verifyFormat("class A {\n} a, b;");
verifyFormat("struct A {\n} a, b;");
@@ -2243,33 +1217,43 @@ TEST_F(FormatTest, FormatsBitfields) {
}
TEST_F(FormatTest, FormatsNamespaces) {
+ FormatStyle LLVMWithNoNamespaceFix = getLLVMStyle();
+ LLVMWithNoNamespaceFix.FixNamespaceComments = false;
+
verifyFormat("namespace some_namespace {\n"
"class A {};\n"
"void f() { f(); }\n"
- "}");
+ "}",
+ LLVMWithNoNamespaceFix);
verifyFormat("namespace {\n"
"class A {};\n"
"void f() { f(); }\n"
- "}");
+ "}",
+ LLVMWithNoNamespaceFix);
verifyFormat("inline namespace X {\n"
"class A {};\n"
"void f() { f(); }\n"
- "}");
+ "}",
+ LLVMWithNoNamespaceFix);
verifyFormat("using namespace some_namespace;\n"
"class A {};\n"
- "void f() { f(); }");
+ "void f() { f(); }",
+ LLVMWithNoNamespaceFix);
// This code is more common than we thought; if we
// layout this correctly the semicolon will go into
// its own line, which is undesirable.
- verifyFormat("namespace {};");
+ verifyFormat("namespace {};",
+ LLVMWithNoNamespaceFix);
verifyFormat("namespace {\n"
"class A {};\n"
- "};");
+ "};",
+ LLVMWithNoNamespaceFix);
verifyFormat("namespace {\n"
"int SomeVariable = 0; // comment\n"
- "} // namespace");
+ "} // namespace",
+ LLVMWithNoNamespaceFix);
EXPECT_EQ("#ifndef HEADER_GUARD\n"
"#define HEADER_GUARD\n"
"namespace my_namespace {\n"
@@ -2281,14 +1265,16 @@ TEST_F(FormatTest, FormatsNamespaces) {
" namespace my_namespace {\n"
"int i;\n"
"} // my_namespace\n"
- "#endif // HEADER_GUARD"));
+ "#endif // HEADER_GUARD",
+ LLVMWithNoNamespaceFix));
EXPECT_EQ("namespace A::B {\n"
"class C {};\n"
"}",
format("namespace A::B {\n"
"class C {};\n"
- "}"));
+ "}",
+ LLVMWithNoNamespaceFix));
FormatStyle Style = getLLVMStyle();
Style.NamespaceIndentation = FormatStyle::NI_All;
@@ -2296,14 +1282,14 @@ TEST_F(FormatTest, FormatsNamespaces) {
" int i;\n"
" namespace in {\n"
" int i;\n"
- " } // namespace\n"
- "} // namespace",
+ " } // namespace in\n"
+ "} // namespace out",
format("namespace out {\n"
"int i;\n"
"namespace in {\n"
"int i;\n"
- "} // namespace\n"
- "} // namespace",
+ "} // namespace in\n"
+ "} // namespace out",
Style));
Style.NamespaceIndentation = FormatStyle::NI_Inner;
@@ -2311,14 +1297,14 @@ TEST_F(FormatTest, FormatsNamespaces) {
"int i;\n"
"namespace in {\n"
" int i;\n"
- "} // namespace\n"
- "} // namespace",
+ "} // namespace in\n"
+ "} // namespace out",
format("namespace out {\n"
"int i;\n"
"namespace in {\n"
"int i;\n"
- "} // namespace\n"
- "} // namespace",
+ "} // namespace in\n"
+ "} // namespace out",
Style));
}
@@ -2822,11 +1808,11 @@ TEST_F(FormatTest, MacrosWithoutTrailingSemicolon) {
EXPECT_EQ("SOME_MACRO\n"
"namespace {\n"
"void f();\n"
- "}",
+ "} // namespace",
format("SOME_MACRO\n"
" namespace {\n"
"void f( );\n"
- "}"));
+ "} // namespace"));
// Only if the identifier contains at least 5 characters.
EXPECT_EQ("HTTP f();", format("HTTP\nf();"));
EXPECT_EQ("MACRO\nf();", format("MACRO\nf();"));
@@ -3021,21 +2007,10 @@ TEST_F(FormatTest, EscapedNewlines) {
format("#define A \\\nint i;\\\n int j;", getLLVMStyleWithColumns(11)));
EXPECT_EQ("#define A\n\nint i;", format("#define A \\\n\n int i;"));
EXPECT_EQ("template <class T> f();", format("\\\ntemplate <class T> f();"));
- EXPECT_EQ("/* \\ \\ \\\n*/", format("\\\n/* \\ \\ \\\n*/"));
+ EXPECT_EQ("/* \\ \\ \\\n */", format("\\\n/* \\ \\ \\\n */"));
EXPECT_EQ("<a\n\\\\\n>", format("<a\n\\\\\n>"));
}
-TEST_F(FormatTest, DontCrashOnBlockComments) {
- EXPECT_EQ(
- "int xxxxxxxxx; /* "
- "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\n"
- "zzzzzz\n"
- "0*/",
- format("int xxxxxxxxx; /* "
- "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy zzzzzz\n"
- "0*/"));
-}
-
TEST_F(FormatTest, CalculateSpaceOnConsecutiveLinesInMacro) {
verifyFormat("#define A \\\n"
" int v( \\\n"
@@ -3353,9 +2328,10 @@ TEST_F(FormatTest, PreventConfusingIndents) {
" aaaaaaaaaaaaaaaaaaaaaaaa<\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>,\n"
" aaaaaaaaaaaaaaaaaaaaaaaa>;");
- verifyFormat("int a = bbbb && ccc && fffff(\n"
+ verifyFormat("int a = bbbb && ccc &&\n"
+ " fffff(\n"
"#define A Just forcing a new line\n"
- " ddd);");
+ " ddd);");
}
TEST_F(FormatTest, LineBreakingInBinaryExpressions) {
@@ -3438,6 +2414,12 @@ TEST_F(FormatTest, LineBreakingInBinaryExpressions) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n}",
OnePerLine);
+
+ verifyFormat("int i = someFunction(aaaaaaa, 0)\n"
+ " .aaa(aaaaaaaaaaaaa) *\n"
+ " aaaaaaa +\n"
+ " aaaaaaa;",
+ getLLVMStyleWithColumns(40));
}
TEST_F(FormatTest, ExpressionIndentation) {
@@ -3463,9 +2445,14 @@ TEST_F(FormatTest, ExpressionIndentation) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}");
verifyFormat("if () {\n"
+ "} else if (aaaaa && bbbbb > // break\n"
+ " ccccc) {\n"
+ "}");
+ verifyFormat("if () {\n"
"} else if (aaaaa &&\n"
" bbbbb > // break\n"
- " ccccc) {\n"
+ " ccccc &&\n"
+ " ddddd) {\n"
"}");
// Presence of a trailing comment used to change indentation of b.
@@ -3549,9 +2536,22 @@ TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) {
Style);
}
+TEST_F(FormatTest, EnforcedOperatorWraps) {
+ // Here we'd like to wrap after the || operators, but a comment is forcing an
+ // earlier wrap.
+ verifyFormat("bool x = aaaaa //\n"
+ " || bbbbb\n"
+ " //\n"
+ " || cccc;");
+}
+
TEST_F(FormatTest, NoOperandAlignment) {
FormatStyle Style = getLLVMStyle();
Style.AlignOperands = false;
+ verifyFormat("aaaaaaaaaaaaaa(aaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
verifyFormat("bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
@@ -3570,7 +2570,7 @@ TEST_F(FormatTest, NoOperandAlignment) {
Style);
verifyFormat("int a = aa\n"
" + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
- " * cccccccccccccccccccccccccccccccccccc;",
+ " * cccccccccccccccccccccccccccccccccccc;\n",
Style);
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
@@ -4044,8 +3044,9 @@ TEST_F(FormatTest, BreaksDesireably) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa));");
verifyFormat(
- "aaaaaaaa(aaaaaaaaaaaaa, aaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)),\n"
+ "aaaaaaaa(aaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)),\n"
" aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)));");
@@ -4063,6 +3064,11 @@ TEST_F(FormatTest, BreaksDesireably) {
verifyFormat(
"aaaaaa(aaa, new Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaa));");
+ verifyFormat(
+ "aaaaaa(aaa,\n"
+ " new Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaa);");
verifyFormat("aaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
@@ -4541,11 +3547,18 @@ TEST_F(FormatTest, ParenthesesAndOperandAlignment) {
TEST_F(FormatTest, BreaksConditionalExpressions) {
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaa(aaaaaaaaaa, aaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaa(aaaaaaaaa, aaaaaaaaa,\n"
" aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat(
@@ -4620,10 +3633,9 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" aaaaaaaaaaaaaaaaaaaaa\n"
" : aaaaaaaaaa;");
verifyFormat(
- "aaaaaa = aaaaaaaaaaaa\n"
- " ? aaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " : aaaaaaaaaaaaaaaaaaaaaa\n"
- " : aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ "aaaaaa = aaaaaaaaaaaa ? aaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
FormatStyle NoBinPacking = getLLVMStyle();
NoBinPacking.BinPackArguments = false;
@@ -4677,12 +3689,21 @@ TEST_F(FormatTest, BreaksConditionalExpressionsAfterOperator) {
Style.BreakBeforeTernaryOperators = false;
Style.ColumnLimit = 70;
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
+ "aaaa(aaaaaaaaaa, aaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
Style);
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
+ "aaaa(aaaaaaaa, aaaaaaaaaa,\n"
" aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
Style);
@@ -4823,7 +3844,7 @@ TEST_F(FormatTest, AlignsStringLiterals) {
EXPECT_EQ("fun + \"1243\" /* comment */\n"
" \"5678\";",
format("fun + \"1243\" /* comment */\n"
- " \"5678\";",
+ " \"5678\";",
getLLVMStyleWithColumns(28)));
EXPECT_EQ(
"aaaaaa = \"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaa \"\n"
@@ -5069,9 +4090,9 @@ TEST_F(FormatTest, AlwaysBreakBeforeMultilineStrings) {
"c\";",
Break));
- // Exempt ObjC strings for now.
- EXPECT_EQ("NSString *const kString = @\"aaaa\"\n"
- " @\"bbbb\";",
+ EXPECT_EQ("NSString *const kString =\n"
+ " @\"aaaa\"\n"
+ " @\"bbbb\";",
format("NSString *const kString = @\"aaaa\"\n"
"@\"bbbb\";",
Break));
@@ -5111,6 +4132,9 @@ TEST_F(FormatTest, AlignsPipes) {
verifyFormat(
"llvm::errs() << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "auto Diag = diag() << aaaaaaaaaaaaaaaa(aaaaaaaaaaaa, aaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat("llvm::outs() << \"aaaaaaaaaaaaaaaa: \"\n"
" << aaaaaaaa.aaaaaaaaaaaa(aaa)->aaaaaaaaaaaaaa();");
@@ -5425,6 +4449,44 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) {
"};");
}
+TEST_F(FormatTest, WrapsTemplateParameters) {
+ FormatStyle Style = getLLVMStyle();
+ Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
+ verifyFormat(
+ "template <typename... a> struct q {};\n"
+ "extern q<aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa>\n"
+ " y;",
+ Style);
+ Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
+ verifyFormat(
+ "template <typename... a> struct r {};\n"
+ "extern r<aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa>\n"
+ " y;",
+ Style);
+ Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
+ verifyFormat(
+ "template <typename... a> struct s {};\n"
+ "extern s<\n"
+ " aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa>\n"
+ " y;",
+ Style);
+ Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
+ verifyFormat(
+ "template <typename... a> struct t {};\n"
+ "extern t<\n"
+ " aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa>\n"
+ " y;",
+ Style);
+}
+
TEST_F(FormatTest, WrapsAtNestedNameSpecifiers) {
verifyFormat(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
@@ -5450,8 +4512,9 @@ TEST_F(FormatTest, WrapsAtNestedNameSpecifiers) {
" aaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat(
- "aaaaaaaaaaaaaaaaaa(aaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ "aaaaaaaaaaaaaaaaaa(aaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaa);",
getLLVMStyleWithColumns(74));
@@ -5893,10 +4956,17 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyFormat("foo<b & 1>();");
verifyFormat("decltype(*::std::declval<const T &>()) void F();");
verifyFormat(
+ "template <class T, class = typename std::enable_if<\n"
+ " std::is_integral<T>::value &&\n"
+ " (sizeof(T) > 1 || sizeof(T) < 8)>::type>\n"
+ "void F();",
+ getLLVMStyleWithColumns(70));
+ verifyFormat(
"template <class T,\n"
" class = typename std::enable_if<\n"
" std::is_integral<T>::value &&\n"
- " (sizeof(T) > 1 || sizeof(T) < 8)>::type>\n"
+ " (sizeof(T) > 1 || sizeof(T) < 8)>::type,\n"
+ " class U>\n"
"void F();",
getLLVMStyleWithColumns(70));
verifyFormat(
@@ -5909,6 +4979,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("MACRO(int *i);");
verifyIndependentOfContext("MACRO(auto *a);");
verifyIndependentOfContext("MACRO(const A *a);");
+ verifyIndependentOfContext("MACRO(A *const a);");
verifyIndependentOfContext("MACRO('0' <= c && c <= '9');");
verifyFormat("void f() { f(float{1}, a * a); }");
// FIXME: Is there a way to make this work?
@@ -6173,6 +5244,11 @@ TEST_F(FormatTest, BreaksLongVariableDeclarations) {
" LoooooooooooooooooooooooooooooooooooooooongVariable({});");
verifyFormat("LoooooooooooooooooooooooooooooooooooooooongType\n"
" LoooooooooooooooooooooooooooooooooooooongVariable([A a]);");
+
+ // Lambdas should not confuse the variable declaration heuristic.
+ verifyFormat("LooooooooooooooooongType\n"
+ " variable(nullptr, [](A *a) {});",
+ getLLVMStyleWithColumns(40));
}
TEST_F(FormatTest, BreaksLongDeclarations) {
@@ -6264,6 +5340,11 @@ TEST_F(FormatTest, BreaksLongDeclarations) {
" vector<aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>>\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ verifyFormat("template <typename T> // Templates on own line.\n"
+ "static int // Some comment.\n"
+ "MyFunction(int a);",
+ getLLVMStyle());
}
TEST_F(FormatTest, FormatsArrays) {
@@ -6333,6 +5414,11 @@ TEST_F(FormatTest, HandlesIncludeDirectives) {
verifyFormat("#define MY_IMPORT <a/b>");
+ verifyFormat("#if __has_include(<a/b>)");
+ verifyFormat("#if __has_include_next(<a/b>)");
+ verifyFormat("#define F __has_include(<a/b>)");
+ verifyFormat("#define F __has_include_next(<a/b>)");
+
// Protocol buffer definition or missing "#".
verifyFormat("import \"aaaaaaaaaaaaaaaaa/aaaaaaaaaaaaaaa\";",
getLLVMStyleWithColumns(30));
@@ -6393,7 +5479,7 @@ TEST_F(FormatTest, IncorrectCodeMissingSemicolon) {
EXPECT_EQ("namespace N {\n"
"void f() {}\n"
"void g()\n"
- "}",
+ "} // namespace N",
format("namespace N { void f( ) { } void g( ) }"));
}
@@ -6453,7 +5539,7 @@ TEST_F(FormatTest, DoesNotTouchUnwrappedLinesWithErrors) {
verifyIncompleteFormat("namespace {\n"
"class Foo { Foo (\n"
"};\n"
- "} // comment");
+ "} // namespace");
}
TEST_F(FormatTest, IncorrectCodeErrorDetection) {
@@ -6818,7 +5904,10 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
"};");
// Don't create hanging lists.
- verifyFormat("someFunction(Param,\n"
+ verifyFormat("someFunction(Param, {List1, List2,\n"
+ " List3});",
+ getLLVMStyleWithColumns(35));
+ verifyFormat("someFunction(Param, Param,\n"
" {List1, List2,\n"
" List3});",
getLLVMStyleWithColumns(35));
@@ -7059,188 +6148,6 @@ TEST_F(FormatTest, MergeHandlingInTheFaceOfPreprocessorDirectives) {
ShortMergedIf);
}
-TEST_F(FormatTest, BlockCommentsInControlLoops) {
- verifyFormat("if (0) /* a comment in a strange place */ {\n"
- " f();\n"
- "}");
- verifyFormat("if (0) /* a comment in a strange place */ {\n"
- " f();\n"
- "} /* another comment */ else /* comment #3 */ {\n"
- " g();\n"
- "}");
- verifyFormat("while (0) /* a comment in a strange place */ {\n"
- " f();\n"
- "}");
- verifyFormat("for (;;) /* a comment in a strange place */ {\n"
- " f();\n"
- "}");
- verifyFormat("do /* a comment in a strange place */ {\n"
- " f();\n"
- "} /* another comment */ while (0);");
-}
-
-TEST_F(FormatTest, BlockComments) {
- EXPECT_EQ("/* */ /* */ /* */\n/* */ /* */ /* */",
- format("/* *//* */ /* */\n/* *//* */ /* */"));
- EXPECT_EQ("/* */ a /* */ b;", format(" /* */ a/* */ b;"));
- EXPECT_EQ("#define A /*123*/ \\\n"
- " b\n"
- "/* */\n"
- "someCall(\n"
- " parameter);",
- format("#define A /*123*/ b\n"
- "/* */\n"
- "someCall(parameter);",
- getLLVMStyleWithColumns(15)));
-
- EXPECT_EQ("#define A\n"
- "/* */ someCall(\n"
- " parameter);",
- format("#define A\n"
- "/* */someCall(parameter);",
- getLLVMStyleWithColumns(15)));
- EXPECT_EQ("/*\n**\n*/", format("/*\n**\n*/"));
- EXPECT_EQ("/*\n"
- "*\n"
- " * aaaaaa\n"
- " * aaaaaa\n"
- "*/",
- format("/*\n"
- "*\n"
- " * aaaaaa aaaaaa\n"
- "*/",
- getLLVMStyleWithColumns(10)));
- EXPECT_EQ("/*\n"
- "**\n"
- "* aaaaaa\n"
- "*aaaaaa\n"
- "*/",
- format("/*\n"
- "**\n"
- "* aaaaaa aaaaaa\n"
- "*/",
- getLLVMStyleWithColumns(10)));
- EXPECT_EQ("int aaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
- " /* line 1\n"
- " bbbbbbbbbbbb */\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
- format("int aaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
- " /* line 1\n"
- " bbbbbbbbbbbb */ bbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
- getLLVMStyleWithColumns(50)));
-
- FormatStyle NoBinPacking = getLLVMStyle();
- NoBinPacking.BinPackParameters = false;
- EXPECT_EQ("someFunction(1, /* comment 1 */\n"
- " 2, /* comment 2 */\n"
- " 3, /* comment 3 */\n"
- " aaaa,\n"
- " bbbb);",
- format("someFunction (1, /* comment 1 */\n"
- " 2, /* comment 2 */ \n"
- " 3, /* comment 3 */\n"
- "aaaa, bbbb );",
- NoBinPacking));
- verifyFormat(
- "bool aaaaaaaaaaaaa = /* comment: */ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
- EXPECT_EQ(
- "bool aaaaaaaaaaaaa = /* trailing comment */\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaa;",
- format(
- "bool aaaaaaaaaaaaa = /* trailing comment */\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa||aaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaa;"));
- EXPECT_EQ(
- "int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; /* comment */\n"
- "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; /* comment */\n"
- "int cccccccccccccccccccccccccccccc; /* comment */\n",
- format("int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; /* comment */\n"
- "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; /* comment */\n"
- "int cccccccccccccccccccccccccccccc; /* comment */\n"));
-
- verifyFormat("void f(int * /* unused */) {}");
-
- EXPECT_EQ("/*\n"
- " **\n"
- " */",
- format("/*\n"
- " **\n"
- " */"));
- EXPECT_EQ("/*\n"
- " *q\n"
- " */",
- format("/*\n"
- " *q\n"
- " */"));
- EXPECT_EQ("/*\n"
- " * q\n"
- " */",
- format("/*\n"
- " * q\n"
- " */"));
- EXPECT_EQ("/*\n"
- " **/",
- format("/*\n"
- " **/"));
- EXPECT_EQ("/*\n"
- " ***/",
- format("/*\n"
- " ***/"));
-}
-
-TEST_F(FormatTest, BlockCommentsInMacros) {
- EXPECT_EQ("#define A \\\n"
- " { \\\n"
- " /* one line */ \\\n"
- " someCall();",
- format("#define A { \\\n"
- " /* one line */ \\\n"
- " someCall();",
- getLLVMStyleWithColumns(20)));
- EXPECT_EQ("#define A \\\n"
- " { \\\n"
- " /* previous */ \\\n"
- " /* one line */ \\\n"
- " someCall();",
- format("#define A { \\\n"
- " /* previous */ \\\n"
- " /* one line */ \\\n"
- " someCall();",
- getLLVMStyleWithColumns(20)));
-}
-
-TEST_F(FormatTest, BlockCommentsAtEndOfLine) {
- EXPECT_EQ("a = {\n"
- " 1111 /* */\n"
- "};",
- format("a = {1111 /* */\n"
- "};",
- getLLVMStyleWithColumns(15)));
- EXPECT_EQ("a = {\n"
- " 1111 /* */\n"
- "};",
- format("a = {1111 /* */\n"
- "};",
- getLLVMStyleWithColumns(15)));
-
- // FIXME: The formatting is still wrong here.
- EXPECT_EQ("a = {\n"
- " 1111 /* a\n"
- " */\n"
- "};",
- format("a = {1111 /* a */\n"
- "};",
- getLLVMStyleWithColumns(15)));
-}
-
-TEST_F(FormatTest, IndentLineCommentsInStartOfBlockAtEndOfFile) {
- verifyFormat("{\n"
- " // a\n"
- " // b");
-}
-
TEST_F(FormatTest, FormatStarDependingOnContext) {
verifyFormat("void f(int *a);");
verifyFormat("void f() { f(fint * b); }");
@@ -7252,8 +6159,8 @@ TEST_F(FormatTest, FormatStarDependingOnContext) {
" void f() {}\n"
" int *a;\n"
"};\n"
- "}\n"
- "}");
+ "} // namespace b\n"
+ "} // namespace a");
}
TEST_F(FormatTest, SpecialTokensAtEndOfLine) {
@@ -7553,6 +6460,7 @@ TEST_F(FormatTest, BreaksWideAndNSStringLiterals) {
EXPECT_EQ("@\"NSString \"\n"
"@\"literal\";",
format("@\"NSString literal\";", getGoogleStyleWithColumns(19)));
+ verifyFormat(R"(NSString *s = @"那那那那";)", getLLVMStyleWithColumns(26));
// This input makes clang-format try to split the incomplete unicode escape
// sequence, which used to lead to a crasher.
@@ -7578,8 +6486,9 @@ TEST_F(FormatTest, BreaksStringLiteralsWithin_TMacro) {
"_T(\"aaaaaaaaaaaaaa\")\n"
"_T(\"aaaaaaaaaaaa\")",
format(" _T(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\")", Style));
- EXPECT_EQ("f(x, _T(\"aaaaaaaaa\")\n"
- " _T(\"aaaaaa\"),\n"
+ EXPECT_EQ("f(x,\n"
+ " _T(\"aaaaaaaaaaaa\")\n"
+ " _T(\"aaa\"),\n"
" z);",
format("f(x, _T(\"aaaaaaaaaaaaaaa\"), z);", Style));
@@ -7611,6 +6520,90 @@ TEST_F(FormatTest, BreaksStringLiteralsWithin_TMacro) {
"_T(\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXn\"));"));
}
+TEST_F(FormatTest, BreaksStringLiteralOperands) {
+ // In a function call with two operands, the second can be broken with no line
+ // break before it.
+ EXPECT_EQ("func(a, \"long long \"\n"
+ " \"long long\");",
+ format("func(a, \"long long long long\");",
+ getLLVMStyleWithColumns(24)));
+ // In a function call with three operands, the second must be broken with a
+ // line break before it.
+ EXPECT_EQ("func(a,\n"
+ " \"long long long \"\n"
+ " \"long\",\n"
+ " c);",
+ format("func(a, \"long long long long\", c);",
+ getLLVMStyleWithColumns(24)));
+ // In a function call with three operands, the third must be broken with a
+ // line break before it.
+ EXPECT_EQ("func(a, b,\n"
+ " \"long long long \"\n"
+ " \"long\");",
+ format("func(a, b, \"long long long long\");",
+ getLLVMStyleWithColumns(24)));
+ // In a function call with three operands, both the second and the third must
+ // be broken with a line break before them.
+ EXPECT_EQ("func(a,\n"
+ " \"long long long \"\n"
+ " \"long\",\n"
+ " \"long long long \"\n"
+ " \"long\");",
+ format("func(a, \"long long long long\", \"long long long long\");",
+ getLLVMStyleWithColumns(24)));
+ // In a chain of << with two operands, the second can be broken with no line
+ // break before it.
+ EXPECT_EQ("a << \"line line \"\n"
+ " \"line\";",
+ format("a << \"line line line\";",
+ getLLVMStyleWithColumns(20)));
+ // In a chain of << with three operands, the second can be broken with no line
+ // break before it.
+ EXPECT_EQ("abcde << \"line \"\n"
+ " \"line line\"\n"
+ " << c;",
+ format("abcde << \"line line line\" << c;",
+ getLLVMStyleWithColumns(20)));
+ // In a chain of << with three operands, the third must be broken with a line
+ // break before it.
+ EXPECT_EQ("a << b\n"
+ " << \"line line \"\n"
+ " \"line\";",
+ format("a << b << \"line line line\";",
+ getLLVMStyleWithColumns(20)));
+ // In a chain of << with three operands, the second can be broken with no line
+ // break before it and the third must be broken with a line break before it.
+ EXPECT_EQ("abcd << \"line line \"\n"
+ " \"line\"\n"
+ " << \"line line \"\n"
+ " \"line\";",
+ format("abcd << \"line line line\" << \"line line line\";",
+ getLLVMStyleWithColumns(20)));
+ // In a chain of binary operators with two operands, the second can be broken
+ // with no line break before it.
+ EXPECT_EQ("abcd + \"line line \"\n"
+ " \"line line\";",
+ format("abcd + \"line line line line\";",
+ getLLVMStyleWithColumns(20)));
+ // In a chain of binary operators with three operands, the second must be
+ // broken with a line break before it.
+ EXPECT_EQ("abcd +\n"
+ " \"line line \"\n"
+ " \"line line\" +\n"
+ " e;",
+ format("abcd + \"line line line line\" + e;",
+ getLLVMStyleWithColumns(20)));
+ // In a function call with two operands, with AlignAfterOpenBracket enabled,
+ // the first must be broken with a line break before it.
+ FormatStyle Style = getLLVMStyleWithColumns(25);
+ Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+ EXPECT_EQ("someFunction(\n"
+ " \"long long long \"\n"
+ " \"long\",\n"
+ " a);",
+ format("someFunction(\"long long long long\", a);", Style));
+}
+
TEST_F(FormatTest, DontSplitStringLiteralsWithEscapedNewlines) {
EXPECT_EQ(
"aaaaaaaaaaa = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
@@ -8680,12 +7673,11 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) {
"};",
Alignment);
- // FIXME: Should align all three assignments
verifyFormat(
"int i = 1;\n"
"SomeType a = SomeFunction(looooooooooooooooooooooongParameterA,\n"
" loooooooooooooooooooooongParameterB);\n"
- "int j = 2;",
+ "int j = 2;",
Alignment);
verifyFormat("template <typename T, typename T_0 = very_long_type_name_0,\n"
@@ -8700,6 +7692,13 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) {
verifyFormat("int aa = ((1 > 2) ? 3 : 4);\n"
"float b[1][] = {{3.f}};\n",
Alignment);
+ verifyFormat("for (int i = 0; i < 1; i++)\n"
+ " int x = 1;\n",
+ Alignment);
+ verifyFormat("for (i = 0; i < 1; i++)\n"
+ " x = 1;\n"
+ "y = 1;\n",
+ Alignment);
}
TEST_F(FormatTest, AlignConsecutiveDeclarations) {
@@ -8767,7 +7766,57 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) {
"unsigned oneTwoThree = 123;\n"
"int oneTwo = 12;",
Alignment));
+ // Function prototype alignment
+ verifyFormat("int a();\n"
+ "double b();",
+ Alignment);
+ verifyFormat("int a(int x);\n"
+ "double b();",
+ Alignment);
+ unsigned OldColumnLimit = Alignment.ColumnLimit;
+ // We need to set ColumnLimit to zero, in order to stress nested alignments,
+ // otherwise the function parameters will be re-flowed onto a single line.
+ Alignment.ColumnLimit = 0;
+ EXPECT_EQ("int a(int x,\n"
+ " float y);\n"
+ "double b(int x,\n"
+ " double y);",
+ format("int a(int x,\n"
+ " float y);\n"
+ "double b(int x,\n"
+ " double y);",
+ Alignment));
+ // This ensures that function parameters of function declarations are
+ // correctly indented when their owning functions are indented.
+ // The failure case here is for 'double y' to not be indented enough.
+ EXPECT_EQ("double a(int x);\n"
+ "int b(int y,\n"
+ " double z);",
+ format("double a(int x);\n"
+ "int b(int y,\n"
+ " double z);",
+ Alignment));
+ // Set ColumnLimit low so that we induce wrapping immediately after
+ // the function name and opening paren.
+ Alignment.ColumnLimit = 13;
+ verifyFormat("int function(\n"
+ " int x,\n"
+ " bool y);",
+ Alignment);
+ Alignment.ColumnLimit = OldColumnLimit;
+ // Ensure function pointers don't screw up recursive alignment
+ verifyFormat("int a(int x, void (*fp)(int y));\n"
+ "double b();",
+ Alignment);
Alignment.AlignConsecutiveAssignments = true;
+ // Ensure recursive alignment is broken by function braces, so that the
+ // "a = 1" does not align with subsequent assignments inside the function
+ // body.
+ verifyFormat("int func(int a = 1) {\n"
+ " int b = 2;\n"
+ " int cc = 3;\n"
+ "}",
+ Alignment);
verifyFormat("float something = 2000;\n"
"double another = 911;\n"
"int i = 1, j = 10;\n"
@@ -8777,6 +7826,28 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) {
verifyFormat("int oneTwoThree = {0}; // comment\n"
"unsigned oneTwo = 0; // comment",
Alignment);
+ // Make sure that scope is correctly tracked, in the absence of braces
+ verifyFormat("for (int i = 0; i < n; i++)\n"
+ " j = i;\n"
+ "double x = 1;\n",
+ Alignment);
+ verifyFormat("if (int i = 0)\n"
+ " j = i;\n"
+ "double x = 1;\n",
+ Alignment);
+ // Ensure operator[] and operator() are comprehended
+ verifyFormat("struct test {\n"
+ " long long int foo();\n"
+ " int operator[](int a);\n"
+ " double bar();\n"
+ "};\n",
+ Alignment);
+ verifyFormat("struct test {\n"
+ " long long int foo();\n"
+ " int operator()(int a);\n"
+ " double bar();\n"
+ "};\n",
+ Alignment);
EXPECT_EQ("void SomeFunction(int parameter = 0) {\n"
" int const i = 1;\n"
" int * j = 2;\n"
@@ -8878,17 +7949,16 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) {
Alignment);
Alignment.AlignConsecutiveAssignments = false;
- // FIXME: Should align all three declarations
verifyFormat(
"int i = 1;\n"
"SomeType a = SomeFunction(looooooooooooooooooooooongParameterA,\n"
" loooooooooooooooooooooongParameterB);\n"
- "int j = 2;",
+ "int j = 2;",
Alignment);
// Test interactions with ColumnLimit and AlignConsecutiveAssignments:
// We expect declarations and assignments to align, as long as it doesn't
- // exceed the column limit, starting a new alignemnt sequence whenever it
+ // exceed the column limit, starting a new alignment sequence whenever it
// happens.
Alignment.AlignConsecutiveAssignments = true;
Alignment.ColumnLimit = 30;
@@ -8987,6 +8057,7 @@ TEST_F(FormatTest, LinuxBraceBreaking) {
TEST_F(FormatTest, MozillaBraceBreaking) {
FormatStyle MozillaBraceStyle = getLLVMStyle();
MozillaBraceStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
+ MozillaBraceStyle.FixNamespaceComments = false;
verifyFormat("namespace a {\n"
"class A\n"
"{\n"
@@ -9045,7 +8116,7 @@ TEST_F(FormatTest, StroustrupBraceBreaking) {
"struct B {\n"
" int x;\n"
"};\n"
- "}\n",
+ "} // namespace a\n",
StroustrupBraceStyle);
verifyFormat("void foo()\n"
@@ -9231,7 +8302,14 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
// .. or dict literals.
verifyFormat("void f()\n"
"{\n"
- " [object someMethod:@{ @\"a\" : @\"b\" }];\n"
+ " // ...\n"
+ " [object someMethod:@{@\"a\" : @\"b\"}];\n"
+ "}",
+ AllmanBraceStyle);
+ verifyFormat("void f()\n"
+ "{\n"
+ " // ...\n"
+ " [object someMethod:@{a : @\"b\"}];\n"
"}",
AllmanBraceStyle);
verifyFormat("int f()\n"
@@ -9403,6 +8481,7 @@ TEST_F(FormatTest, GNUBraceBreaking) {
TEST_F(FormatTest, WebKitBraceBreaking) {
FormatStyle WebKitBraceStyle = getLLVMStyle();
WebKitBraceStyle.BreakBeforeBraces = FormatStyle::BS_WebKit;
+ WebKitBraceStyle.FixNamespaceComments = false;
verifyFormat("namespace a {\n"
"class A {\n"
" void f()\n"
@@ -9602,6 +8681,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
CHECK_PARSE_BOOL(BreakConstructorInitializersBeforeComma);
CHECK_PARSE_BOOL(BreakStringLiterals);
+ CHECK_PARSE_BOOL(BreakBeforeInheritanceComma)
CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
CHECK_PARSE_BOOL(DerivePointerAlignment);
CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
@@ -10403,10 +9483,11 @@ TEST_F(FormatTest, FormatsLambdas) {
" << std::count_if(v.begin(), v.end(), [](int x) {\n"
" return x == 2; // force break\n"
" });");
- verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa([=](\n"
- " int iiiiiiiiiiii) {\n"
- " return aaaaaaaaaaaaaaaaaaaaaaa != aaaaaaaaaaaaaaaaaaaaaaa;\n"
- "});",
+ verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " [=](int iiiiiiiiiiii) {\n"
+ " return aaaaaaaaaaaaaaaaaaaaaaa !=\n"
+ " aaaaaaaaaaaaaaaaaaaaaaa;\n"
+ " });",
getLLVMStyleWithColumns(60));
verifyFormat("SomeFunction({[&] {\n"
" // comment\n"
@@ -10492,6 +9573,15 @@ TEST_F(FormatTest, FormatsLambdas) {
"#endif\n"
" ;\n"
"};");
+
+ // Lambdas with complex multiline introducers.
+ verifyFormat(
+ "aaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]()\n"
+ " -> ::std::unordered_set<\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n"
+ " //\n"
+ " });");
}
TEST_F(FormatTest, FormatsBlocks) {
@@ -10919,6 +10009,26 @@ TEST_F(FormatTest, DisableRegions) {
" int j;\n"
" /* clang-format on */\n"
" int k;"));
+
+ // Don't reflow comments within disabled regions.
+ EXPECT_EQ(
+ "// clang-format off\n"
+ "// long long long long long long line\n"
+ "/* clang-format on */\n"
+ "/* long long long\n"
+ " * long long long\n"
+ " * line */\n"
+ "int i;\n"
+ "/* clang-format off */\n"
+ "/* long long long long long long line */\n",
+ format("// clang-format off\n"
+ "// long long long long long long line\n"
+ "/* clang-format on */\n"
+ "/* long long long long long long line */\n"
+ "int i;\n"
+ "/* clang-format off */\n"
+ "/* long long long long long long line */\n",
+ getLLVMStyleWithColumns(20)));
}
TEST_F(FormatTest, DoNotCrashOnInvalidInput) {
@@ -10952,6 +10062,10 @@ TEST_F(FormatTest, ArrayAsTemplateType) {
format("auto a = unique_ptr < Foo < Bar>[10]> ;", Spaces));
}
+TEST_F(FormatTest, NoSpaceAfterSuper) {
+ verifyFormat("__super::FooBar();");
+}
+
TEST(FormatStyle, GetStyleOfFile) {
vfs::InMemoryFileSystem FS;
// Test 1: format file in the same directory.
@@ -10961,13 +10075,33 @@ TEST(FormatStyle, GetStyleOfFile) {
ASSERT_TRUE(
FS.addFile("/a/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;")));
auto Style1 = getStyle("file", "/a/.clang-format", "Google", "", &FS);
- ASSERT_EQ(Style1, getLLVMStyle());
+ ASSERT_TRUE((bool)Style1);
+ ASSERT_EQ(*Style1, getLLVMStyle());
- // Test 2: fallback to default.
+ // Test 2.1: fallback to default.
ASSERT_TRUE(
FS.addFile("/b/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;")));
auto Style2 = getStyle("file", "/b/test.cpp", "Mozilla", "", &FS);
- ASSERT_EQ(Style2, getMozillaStyle());
+ ASSERT_TRUE((bool)Style2);
+ ASSERT_EQ(*Style2, getMozillaStyle());
+
+ // Test 2.2: no format on 'none' fallback style.
+ Style2 = getStyle("file", "/b/test.cpp", "none", "", &FS);
+ ASSERT_TRUE((bool)Style2);
+ ASSERT_EQ(*Style2, getNoStyle());
+
+ // Test 2.3: format if config is found with no based style while fallback is
+ // 'none'.
+ ASSERT_TRUE(FS.addFile("/b/.clang-format", 0,
+ llvm::MemoryBuffer::getMemBuffer("IndentWidth: 2")));
+ Style2 = getStyle("file", "/b/test.cpp", "none", "", &FS);
+ ASSERT_TRUE((bool)Style2);
+ ASSERT_EQ(*Style2, getLLVMStyle());
+
+ // Test 2.4: format if yaml with no based style, while fallback is 'none'.
+ Style2 = getStyle("{}", "a.h", "none", "", &FS);
+ ASSERT_TRUE((bool)Style2);
+ ASSERT_EQ(*Style2, getLLVMStyle());
// Test 3: format file in parent directory.
ASSERT_TRUE(
@@ -10976,7 +10110,34 @@ TEST(FormatStyle, GetStyleOfFile) {
ASSERT_TRUE(FS.addFile("/c/sub/sub/sub/test.cpp", 0,
llvm::MemoryBuffer::getMemBuffer("int i;")));
auto Style3 = getStyle("file", "/c/sub/sub/sub/test.cpp", "LLVM", "", &FS);
- ASSERT_EQ(Style3, getGoogleStyle());
+ ASSERT_TRUE((bool)Style3);
+ ASSERT_EQ(*Style3, getGoogleStyle());
+
+ // Test 4: error on invalid fallback style
+ auto Style4 = getStyle("file", "a.h", "KungFu", "", &FS);
+ ASSERT_FALSE((bool)Style4);
+ llvm::consumeError(Style4.takeError());
+
+ // Test 5: error on invalid yaml on command line
+ auto Style5 = getStyle("{invalid_key=invalid_value}", "a.h", "LLVM", "", &FS);
+ ASSERT_FALSE((bool)Style5);
+ llvm::consumeError(Style5.takeError());
+
+ // Test 6: error on invalid style
+ auto Style6 = getStyle("KungFu", "a.h", "LLVM", "", &FS);
+ ASSERT_FALSE((bool)Style6);
+ llvm::consumeError(Style6.takeError());
+
+ // Test 7: found config file, error on parsing it
+ ASSERT_TRUE(
+ FS.addFile("/d/.clang-format", 0,
+ llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: LLVM\n"
+ "InvalidKey: InvalidValue")));
+ ASSERT_TRUE(
+ FS.addFile("/d/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;")));
+ auto Style7 = getStyle("file", "/d/.clang-format", "LLVM", "", &FS);
+ ASSERT_FALSE((bool)Style7);
+ llvm::consumeError(Style7.takeError());
}
TEST_F(ReplacementTest, FormatCodeAfterReplacements) {
@@ -11042,17 +10203,19 @@ TEST_F(ReplacementTest, SortIncludesAfterReplacement) {
EXPECT_EQ(Expected, *Result);
}
-TEST_F(FormatTest, AllignTrailingComments) {
- EXPECT_EQ("#define MACRO(V) \\\n"
- " V(Rt2) /* one more char */ \\\n"
- " V(Rs) /* than here */ \\\n"
- "/* comment 3 */\n",
- format("#define MACRO(V)\\\n"
- "V(Rt2) /* one more char */ \\\n"
- "V(Rs) /* than here */ \\\n"
- "/* comment 3 */ \\\n",
- getLLVMStyleWithColumns(40)));
+TEST_F(FormatTest, UTF8CharacterLiteralCpp03) {
+ format::FormatStyle Style = format::getLLVMStyle();
+ Style.Standard = FormatStyle::LS_Cpp03;
+ // cpp03 recognize this string as identifier u8 and literal character 'a'
+ EXPECT_EQ("auto c = u8 'a';", format("auto c = u8'a';", Style));
}
+
+TEST_F(FormatTest, UTF8CharacterLiteralCpp11) {
+ // u8'a' is a C++17 feature, utf8 literal character, LS_Cpp11 covers
+ // all modes, including C++11, C++14 and C++17
+ EXPECT_EQ("auto c = u8'a';", format("auto c = u8'a';"));
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Format/FormatTestComments.cpp b/unittests/Format/FormatTestComments.cpp
new file mode 100644
index 000000000000..df24abe26125
--- /dev/null
+++ b/unittests/Format/FormatTestComments.cpp
@@ -0,0 +1,2373 @@
+//===- unittest/Format/FormatTestComments.cpp - Formatting unit tests -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Format/Format.h"
+
+#include "../Tooling/ReplacementTest.h"
+#include "FormatTestUtils.h"
+
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "format-test"
+
+using clang::tooling::ReplacementTest;
+
+namespace clang {
+namespace format {
+namespace {
+
+FormatStyle getGoogleStyle() { return getGoogleStyle(FormatStyle::LK_Cpp); }
+
+class FormatTestComments : public ::testing::Test {
+protected:
+ enum IncompleteCheck {
+ IC_ExpectComplete,
+ IC_ExpectIncomplete,
+ IC_DoNotCheck
+ };
+
+ std::string format(llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle(),
+ IncompleteCheck CheckIncomplete = IC_ExpectComplete) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+ bool IncompleteFormat = false;
+ tooling::Replacements Replaces =
+ reformat(Style, Code, Ranges, "<stdin>", &IncompleteFormat);
+ if (CheckIncomplete != IC_DoNotCheck) {
+ bool ExpectedIncompleteFormat = CheckIncomplete == IC_ExpectIncomplete;
+ EXPECT_EQ(ExpectedIncompleteFormat, IncompleteFormat) << Code << "\n\n";
+ }
+ ReplacementCount = Replaces.size();
+ auto Result = applyAllReplacements(Code, Replaces);
+ EXPECT_TRUE(static_cast<bool>(Result));
+ DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+ return *Result;
+ }
+
+ FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
+ FormatStyle Style = getLLVMStyle();
+ Style.ColumnLimit = ColumnLimit;
+ return Style;
+ }
+
+ void verifyFormat(llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle()) {
+ EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
+ }
+
+ void verifyGoogleFormat(llvm::StringRef Code) {
+ verifyFormat(Code, getGoogleStyle());
+ }
+
+ /// \brief Verify that clang-format does not crash on the given input.
+ void verifyNoCrash(llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle()) {
+ format(Code, Style, IC_DoNotCheck);
+ }
+
+ int ReplacementCount;
+};
+
+//===----------------------------------------------------------------------===//
+// Tests for comments.
+//===----------------------------------------------------------------------===//
+
+TEST_F(FormatTestComments, UnderstandsSingleLineComments) {
+ verifyFormat("//* */");
+ verifyFormat("// line 1\n"
+ "// line 2\n"
+ "void f() {}\n");
+
+ verifyFormat("void f() {\n"
+ " // Doesn't do anything\n"
+ "}");
+ verifyFormat("SomeObject\n"
+ " // Calling someFunction on SomeObject\n"
+ " .someFunction();");
+ verifyFormat("auto result = SomeObject\n"
+ " // Calling someFunction on SomeObject\n"
+ " .someFunction();");
+ verifyFormat("void f(int i, // some comment (probably for i)\n"
+ " int j, // some comment (probably for j)\n"
+ " int k); // some comment (probably for k)");
+ verifyFormat("void f(int i,\n"
+ " // some comment (probably for j)\n"
+ " int j,\n"
+ " // some comment (probably for k)\n"
+ " int k);");
+
+ verifyFormat("int i // This is a fancy variable\n"
+ " = 5; // with nicely aligned comment.");
+
+ verifyFormat("// Leading comment.\n"
+ "int a; // Trailing comment.");
+ verifyFormat("int a; // Trailing comment\n"
+ " // on 2\n"
+ " // or 3 lines.\n"
+ "int b;");
+ verifyFormat("int a; // Trailing comment\n"
+ "\n"
+ "// Leading comment.\n"
+ "int b;");
+ verifyFormat("int a; // Comment.\n"
+ " // More details.\n"
+ "int bbbb; // Another comment.");
+ verifyFormat(
+ "int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; // comment\n"
+ "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; // comment\n"
+ "int cccccccccccccccccccccccccccccc; // comment\n"
+ "int ddd; // looooooooooooooooooooooooong comment\n"
+ "int aaaaaaaaaaaaaaaaaaaaaaa; // comment\n"
+ "int bbbbbbbbbbbbbbbbbbbbb; // comment\n"
+ "int ccccccccccccccccccc; // comment");
+
+ verifyFormat("#include \"a\" // comment\n"
+ "#include \"a/b/c\" // comment");
+ verifyFormat("#include <a> // comment\n"
+ "#include <a/b/c> // comment");
+ EXPECT_EQ("#include \"a\" // comment\n"
+ "#include \"a/b/c\" // comment",
+ format("#include \\\n"
+ " \"a\" // comment\n"
+ "#include \"a/b/c\" // comment"));
+
+ verifyFormat("enum E {\n"
+ " // comment\n"
+ " VAL_A, // comment\n"
+ " VAL_B\n"
+ "};");
+
+ EXPECT_EQ("enum A {\n"
+ " // line a\n"
+ " a,\n"
+ " b, // line b\n"
+ "\n"
+ " // line c\n"
+ " c\n"
+ "};",
+ format("enum A {\n"
+ " // line a\n"
+ " a,\n"
+ " b, // line b\n"
+ "\n"
+ " // line c\n"
+ " c\n"
+ "};",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("enum A {\n"
+ " a, // line 1\n"
+ " // line 2\n"
+ "};",
+ format("enum A {\n"
+ " a, // line 1\n"
+ " // line 2\n"
+ "};",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("enum A {\n"
+ " a, // line 1\n"
+ " // line 2\n"
+ "};",
+ format("enum A {\n"
+ " a, // line 1\n"
+ " // line 2\n"
+ "};",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("enum A {\n"
+ " a, // line 1\n"
+ " // line 2\n"
+ " b\n"
+ "};",
+ format("enum A {\n"
+ " a, // line 1\n"
+ " // line 2\n"
+ " b\n"
+ "};",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("enum A {\n"
+ " a, // line 1\n"
+ " // line 2\n"
+ " b\n"
+ "};",
+ format("enum A {\n"
+ " a, // line 1\n"
+ " // line 2\n"
+ " b\n"
+ "};",
+ getLLVMStyleWithColumns(20)));
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; // Trailing comment");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " // Comment inside a statement.\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
+ verifyFormat("SomeFunction(a,\n"
+ " // comment\n"
+ " b + x);");
+ verifyFormat("SomeFunction(a, a,\n"
+ " // comment\n"
+ " b + x);");
+ verifyFormat(
+ "bool aaaaaaaaaaaaa = // comment\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+
+ verifyFormat("int aaaa; // aaaaa\n"
+ "int aa; // aaaaaaa",
+ getLLVMStyleWithColumns(20));
+
+ EXPECT_EQ("void f() { // This does something ..\n"
+ "}\n"
+ "int a; // This is unrelated",
+ format("void f() { // This does something ..\n"
+ " }\n"
+ "int a; // This is unrelated"));
+ EXPECT_EQ("class C {\n"
+ " void f() { // This does something ..\n"
+ " } // awesome..\n"
+ "\n"
+ " int a; // This is unrelated\n"
+ "};",
+ format("class C{void f() { // This does something ..\n"
+ " } // awesome..\n"
+ " \n"
+ "int a; // This is unrelated\n"
+ "};"));
+
+ EXPECT_EQ("int i; // single line trailing comment",
+ format("int i;\\\n// single line trailing comment"));
+
+ verifyGoogleFormat("int a; // Trailing comment.");
+
+ verifyFormat("someFunction(anotherFunction( // Force break.\n"
+ " parameter));");
+
+ verifyGoogleFormat("#endif // HEADER_GUARD");
+
+ verifyFormat("const char *test[] = {\n"
+ " // A\n"
+ " \"aaaa\",\n"
+ " // B\n"
+ " \"aaaaa\"};");
+ verifyGoogleFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaa); // 81_cols_with_this_comment");
+ EXPECT_EQ("D(a, {\n"
+ " // test\n"
+ " int a;\n"
+ "});",
+ format("D(a, {\n"
+ "// test\n"
+ "int a;\n"
+ "});"));
+
+ EXPECT_EQ("lineWith(); // comment\n"
+ "// at start\n"
+ "otherLine();",
+ format("lineWith(); // comment\n"
+ "// at start\n"
+ "otherLine();"));
+ EXPECT_EQ("lineWith(); // comment\n"
+ "/*\n"
+ " * at start */\n"
+ "otherLine();",
+ format("lineWith(); // comment\n"
+ "/*\n"
+ " * at start */\n"
+ "otherLine();"));
+ EXPECT_EQ("lineWith(); // comment\n"
+ " // at start\n"
+ "otherLine();",
+ format("lineWith(); // comment\n"
+ " // at start\n"
+ "otherLine();"));
+
+ EXPECT_EQ("lineWith(); // comment\n"
+ "// at start\n"
+ "otherLine(); // comment",
+ format("lineWith(); // comment\n"
+ "// at start\n"
+ "otherLine(); // comment"));
+ EXPECT_EQ("lineWith();\n"
+ "// at start\n"
+ "otherLine(); // comment",
+ format("lineWith();\n"
+ " // at start\n"
+ "otherLine(); // comment"));
+ EXPECT_EQ("// first\n"
+ "// at start\n"
+ "otherLine(); // comment",
+ format("// first\n"
+ " // at start\n"
+ "otherLine(); // comment"));
+ EXPECT_EQ("f();\n"
+ "// first\n"
+ "// at start\n"
+ "otherLine(); // comment",
+ format("f();\n"
+ "// first\n"
+ " // at start\n"
+ "otherLine(); // comment"));
+ verifyFormat("f(); // comment\n"
+ "// first\n"
+ "// at start\n"
+ "otherLine();");
+ EXPECT_EQ("f(); // comment\n"
+ "// first\n"
+ "// at start\n"
+ "otherLine();",
+ format("f(); // comment\n"
+ "// first\n"
+ " // at start\n"
+ "otherLine();"));
+ EXPECT_EQ("f(); // comment\n"
+ " // first\n"
+ "// at start\n"
+ "otherLine();",
+ format("f(); // comment\n"
+ " // first\n"
+ "// at start\n"
+ "otherLine();"));
+ EXPECT_EQ("void f() {\n"
+ " lineWith(); // comment\n"
+ " // at start\n"
+ "}",
+ format("void f() {\n"
+ " lineWith(); // comment\n"
+ " // at start\n"
+ "}"));
+ EXPECT_EQ("int xy; // a\n"
+ "int z; // b",
+ format("int xy; // a\n"
+ "int z; //b"));
+ EXPECT_EQ("int xy; // a\n"
+ "int z; // bb",
+ format("int xy; // a\n"
+ "int z; //bb",
+ getLLVMStyleWithColumns(12)));
+
+ verifyFormat("#define A \\\n"
+ " int i; /* iiiiiiiiiiiiiiiiiiiii */ \\\n"
+ " int jjjjjjjjjjjjjjjjjjjjjjjj; /* */",
+ getLLVMStyleWithColumns(60));
+ verifyFormat(
+ "#define A \\\n"
+ " int i; /* iiiiiiiiiiiiiiiiiiiii */ \\\n"
+ " int jjjjjjjjjjjjjjjjjjjjjjjj; /* */",
+ getLLVMStyleWithColumns(61));
+
+ verifyFormat("if ( // This is some comment\n"
+ " x + 3) {\n"
+ "}");
+ EXPECT_EQ("if ( // This is some comment\n"
+ " // spanning two lines\n"
+ " x + 3) {\n"
+ "}",
+ format("if( // This is some comment\n"
+ " // spanning two lines\n"
+ " x + 3) {\n"
+ "}"));
+
+ verifyNoCrash("/\\\n/");
+ verifyNoCrash("/\\\n* */");
+ // The 0-character somehow makes the lexer return a proper comment.
+ verifyNoCrash(StringRef("/*\\\0\n/", 6));
+}
+
+TEST_F(FormatTestComments, KeepsParameterWithTrailingCommentsOnTheirOwnLine) {
+ EXPECT_EQ("SomeFunction(a,\n"
+ " b, // comment\n"
+ " c);",
+ format("SomeFunction(a,\n"
+ " b, // comment\n"
+ " c);"));
+ EXPECT_EQ("SomeFunction(a, b,\n"
+ " // comment\n"
+ " c);",
+ format("SomeFunction(a,\n"
+ " b,\n"
+ " // comment\n"
+ " c);"));
+ EXPECT_EQ("SomeFunction(a, b, // comment (unclear relation)\n"
+ " c);",
+ format("SomeFunction(a, b, // comment (unclear relation)\n"
+ " c);"));
+ EXPECT_EQ("SomeFunction(a, // comment\n"
+ " b,\n"
+ " c); // comment",
+ format("SomeFunction(a, // comment\n"
+ " b,\n"
+ " c); // comment"));
+ EXPECT_EQ("aaaaaaaaaa(aaaa(aaaa,\n"
+ " aaaa), //\n"
+ " aaaa, bbbbb);",
+ format("aaaaaaaaaa(aaaa(aaaa,\n"
+ "aaaa), //\n"
+ "aaaa, bbbbb);"));
+}
+
+TEST_F(FormatTestComments, RemovesTrailingWhitespaceOfComments) {
+ EXPECT_EQ("// comment", format("// comment "));
+ EXPECT_EQ("int aaaaaaa, bbbbbbb; // comment",
+ format("int aaaaaaa, bbbbbbb; // comment ",
+ getLLVMStyleWithColumns(33)));
+ EXPECT_EQ("// comment\\\n", format("// comment\\\n \t \v \f "));
+ EXPECT_EQ("// comment \\\n", format("// comment \\\n \t \v \f "));
+}
+
+TEST_F(FormatTestComments, UnderstandsBlockComments) {
+ verifyFormat("f(/*noSpaceAfterParameterNamingComment=*/true);");
+ verifyFormat("void f() { g(/*aaa=*/x, /*bbb=*/!y, /*c=*/::c); }");
+ EXPECT_EQ("f(aaaaaaaaaaaaaaaaaaaaaaaaa, /* Trailing comment for aa... */\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb);",
+ format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , \\\n"
+ "/* Trailing comment for aa... */\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb);"));
+ EXPECT_EQ(
+ "f(aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " /* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);",
+ format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , \n"
+ "/* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);"));
+ EXPECT_EQ(
+ "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaa) { /*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/\n"
+ "}",
+ format("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaa ,\n"
+ " aaaaaaaaaaaaaaaaaa) { /*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/\n"
+ "}"));
+ verifyFormat("f(/* aaaaaaaaaaaaaaaaaa = */\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ verifyFormat("aaaaaaaa(/* parameter 1 */ aaaaaa,\n"
+ " /* parameter 2 */ aaaaaa,\n"
+ " /* parameter 3 */ aaaaaa,\n"
+ " /* parameter 4 */ aaaaaa);",
+ NoBinPacking);
+
+ // Aligning block comments in macros.
+ verifyGoogleFormat("#define A \\\n"
+ " int i; /*a*/ \\\n"
+ " int jjj; /*b*/");
+}
+
+TEST_F(FormatTestComments, AlignsBlockComments) {
+ EXPECT_EQ("/*\n"
+ " * Really multi-line\n"
+ " * comment.\n"
+ " */\n"
+ "void f() {}",
+ format(" /*\n"
+ " * Really multi-line\n"
+ " * comment.\n"
+ " */\n"
+ " void f() {}"));
+ EXPECT_EQ("class C {\n"
+ " /*\n"
+ " * Another multi-line\n"
+ " * comment.\n"
+ " */\n"
+ " void f() {}\n"
+ "};",
+ format("class C {\n"
+ "/*\n"
+ " * Another multi-line\n"
+ " * comment.\n"
+ " */\n"
+ "void f() {}\n"
+ "};"));
+ EXPECT_EQ("/*\n"
+ " 1. This is a comment with non-trivial formatting.\n"
+ " 1.1. We have to indent/outdent all lines equally\n"
+ " 1.1.1. to keep the formatting.\n"
+ " */",
+ format(" /*\n"
+ " 1. This is a comment with non-trivial formatting.\n"
+ " 1.1. We have to indent/outdent all lines equally\n"
+ " 1.1.1. to keep the formatting.\n"
+ " */"));
+ EXPECT_EQ("/*\n"
+ "Don't try to outdent if there's not enough indentation.\n"
+ "*/",
+ format(" /*\n"
+ " Don't try to outdent if there's not enough indentation.\n"
+ " */"));
+
+ EXPECT_EQ("int i; /* Comment with empty...\n"
+ " *\n"
+ " * line. */",
+ format("int i; /* Comment with empty...\n"
+ " *\n"
+ " * line. */"));
+ EXPECT_EQ("int foobar = 0; /* comment */\n"
+ "int bar = 0; /* multiline\n"
+ " comment 1 */\n"
+ "int baz = 0; /* multiline\n"
+ " comment 2 */\n"
+ "int bzz = 0; /* multiline\n"
+ " comment 3 */",
+ format("int foobar = 0; /* comment */\n"
+ "int bar = 0; /* multiline\n"
+ " comment 1 */\n"
+ "int baz = 0; /* multiline\n"
+ " comment 2 */\n"
+ "int bzz = 0; /* multiline\n"
+ " comment 3 */"));
+ EXPECT_EQ("int foobar = 0; /* comment */\n"
+ "int bar = 0; /* multiline\n"
+ " comment */\n"
+ "int baz = 0; /* multiline\n"
+ "comment */",
+ format("int foobar = 0; /* comment */\n"
+ "int bar = 0; /* multiline\n"
+ "comment */\n"
+ "int baz = 0; /* multiline\n"
+ "comment */"));
+}
+
+TEST_F(FormatTestComments, CommentReflowingCanBeTurnedOff) {
+ FormatStyle Style = getLLVMStyleWithColumns(20);
+ Style.ReflowComments = false;
+ verifyFormat("// aaaaaaaaa aaaaaaaaaa aaaaaaaaaa", Style);
+ verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa */", Style);
+}
+
+TEST_F(FormatTestComments, CorrectlyHandlesLengthOfBlockComments) {
+ EXPECT_EQ("double *x; /* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */",
+ format("double *x; /* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */"));
+ EXPECT_EQ(
+ "void ffffffffffff(\n"
+ " int aaaaaaaa, int bbbbbbbb,\n"
+ " int cccccccccccc) { /*\n"
+ " aaaaaaaaaa\n"
+ " aaaaaaaaaaaaa\n"
+ " bbbbbbbbbbbbbb\n"
+ " bbbbbbbbbb\n"
+ " */\n"
+ "}",
+ format("void ffffffffffff(int aaaaaaaa, int bbbbbbbb, int cccccccccccc)\n"
+ "{ /*\n"
+ " aaaaaaaaaa aaaaaaaaaaaaa\n"
+ " bbbbbbbbbbbbbb bbbbbbbbbb\n"
+ " */\n"
+ "}",
+ getLLVMStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestComments, DontBreakNonTrailingBlockComments) {
+ EXPECT_EQ("void ffffffffff(\n"
+ " int aaaaa /* test */);",
+ format("void ffffffffff(int aaaaa /* test */);",
+ getLLVMStyleWithColumns(35)));
+}
+
+TEST_F(FormatTestComments, SplitsLongCxxComments) {
+ EXPECT_EQ("// A comment that\n"
+ "// doesn't fit on\n"
+ "// one line",
+ format("// A comment that doesn't fit on one line",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/// A comment that\n"
+ "/// doesn't fit on\n"
+ "/// one line",
+ format("/// A comment that doesn't fit on one line",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("//! A comment that\n"
+ "//! doesn't fit on\n"
+ "//! one line",
+ format("//! A comment that doesn't fit on one line",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// a b c d\n"
+ "// e f g\n"
+ "// h i j k",
+ format("// a b c d e f g h i j k", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ(
+ "// a b c d\n"
+ "// e f g\n"
+ "// h i j k",
+ format("\\\n// a b c d e f g h i j k", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("if (true) // A comment that\n"
+ " // doesn't fit on\n"
+ " // one line",
+ format("if (true) // A comment that doesn't fit on one line ",
+ getLLVMStyleWithColumns(30)));
+ EXPECT_EQ("// Don't_touch_leading_whitespace",
+ format("// Don't_touch_leading_whitespace",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// Add leading\n"
+ "// whitespace",
+ format("//Add leading whitespace", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/// Add leading\n"
+ "/// whitespace",
+ format("///Add leading whitespace", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("//! Add leading\n"
+ "//! whitespace",
+ format("//!Add leading whitespace", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// whitespace", format("//whitespace", getLLVMStyle()));
+ EXPECT_EQ("// Even if it makes the line exceed the column\n"
+ "// limit",
+ format("//Even if it makes the line exceed the column limit",
+ getLLVMStyleWithColumns(51)));
+ EXPECT_EQ("//--But not here", format("//--But not here", getLLVMStyle()));
+ EXPECT_EQ("/// line 1\n"
+ "// add leading whitespace",
+ format("/// line 1\n"
+ "//add leading whitespace",
+ getLLVMStyleWithColumns(30)));
+ EXPECT_EQ("/// line 1\n"
+ "/// line 2\n"
+ "//! line 3\n"
+ "//! line 4\n"
+ "//! line 5\n"
+ "// line 6\n"
+ "// line 7",
+ format("///line 1\n"
+ "///line 2\n"
+ "//! line 3\n"
+ "//!line 4\n"
+ "//!line 5\n"
+ "// line 6\n"
+ "//line 7", getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("// aa bb cc dd",
+ format("// aa bb cc dd ",
+ getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ("// A comment before\n"
+ "// a macro\n"
+ "// definition\n"
+ "#define a b",
+ format("// A comment before a macro definition\n"
+ "#define a b",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("void ffffff(\n"
+ " int aaaaaaaaa, // wwww\n"
+ " int bbbbbbbbbb, // xxxxxxx\n"
+ " // yyyyyyyyyy\n"
+ " int c, int d, int e) {}",
+ format("void ffffff(\n"
+ " int aaaaaaaaa, // wwww\n"
+ " int bbbbbbbbbb, // xxxxxxx yyyyyyyyyy\n"
+ " int c, int d, int e) {}",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("//\t aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ format("//\t aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ(
+ "#define XXX // a b c d\n"
+ " // e f g h",
+ format("#define XXX // a b c d e f g h", getLLVMStyleWithColumns(22)));
+ EXPECT_EQ(
+ "#define XXX // q w e r\n"
+ " // t y u i",
+ format("#define XXX //q w e r t y u i", getLLVMStyleWithColumns(22)));
+ EXPECT_EQ("{\n"
+ " //\n"
+ " //\\\n"
+ " // long 1 2 3 4\n"
+ " // 5\n"
+ "}",
+ format("{\n"
+ " //\n"
+ " //\\\n"
+ " // long 1 2 3 4 5\n"
+ "}",
+ getLLVMStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestComments, PreservesHangingIndentInCxxComments) {
+ EXPECT_EQ("// A comment\n"
+ "// that doesn't\n"
+ "// fit on one\n"
+ "// line",
+ format("// A comment that doesn't fit on one line",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/// A comment\n"
+ "/// that doesn't\n"
+ "/// fit on one\n"
+ "/// line",
+ format("/// A comment that doesn't fit on one line",
+ getLLVMStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestComments, DontSplitLineCommentsWithEscapedNewlines) {
+ EXPECT_EQ("// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ format("// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
+ "// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ EXPECT_EQ("int a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ format("int a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ getLLVMStyleWithColumns(50)));
+ // FIXME: One day we might want to implement adjustment of leading whitespace
+ // of the consecutive lines in this kind of comment:
+ EXPECT_EQ("double\n"
+ " a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ format("double a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
+ " // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ getLLVMStyleWithColumns(49)));
+}
+
+TEST_F(FormatTestComments, DontSplitLineCommentsWithPragmas) {
+ FormatStyle Pragmas = getLLVMStyleWithColumns(30);
+ Pragmas.CommentPragmas = "^ IWYU pragma:";
+ EXPECT_EQ(
+ "// IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb",
+ format("// IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb", Pragmas));
+ EXPECT_EQ(
+ "/* IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb */",
+ format("/* IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb */", Pragmas));
+}
+
+TEST_F(FormatTestComments, PriorityOfCommentBreaking) {
+ EXPECT_EQ("if (xxx ==\n"
+ " yyy && // aaaaaaaaaaaa bbbbbbbbb\n"
+ " zzz)\n"
+ " q();",
+ format("if (xxx == yyy && // aaaaaaaaaaaa bbbbbbbbb\n"
+ " zzz) q();",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("if (xxxxxxxxxx ==\n"
+ " yyy && // aaaaaa bbbbbbbb cccc\n"
+ " zzz)\n"
+ " q();",
+ format("if (xxxxxxxxxx == yyy && // aaaaaa bbbbbbbb cccc\n"
+ " zzz) q();",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("if (xxxxxxxxxx &&\n"
+ " yyy || // aaaaaa bbbbbbbb cccc\n"
+ " zzz)\n"
+ " q();",
+ format("if (xxxxxxxxxx && yyy || // aaaaaa bbbbbbbb cccc\n"
+ " zzz) q();",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("fffffffff(\n"
+ " &xxx, // aaaaaaaaaaaa bbbbbbbbbbb\n"
+ " zzz);",
+ format("fffffffff(&xxx, // aaaaaaaaaaaa bbbbbbbbbbb\n"
+ " zzz);",
+ getLLVMStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestComments, MultiLineCommentsInDefines) {
+ EXPECT_EQ("#define A(x) /* \\\n"
+ " a comment \\\n"
+ " inside */ \\\n"
+ " f();",
+ format("#define A(x) /* \\\n"
+ " a comment \\\n"
+ " inside */ \\\n"
+ " f();",
+ getLLVMStyleWithColumns(17)));
+ EXPECT_EQ("#define A( \\\n"
+ " x) /* \\\n"
+ " a comment \\\n"
+ " inside */ \\\n"
+ " f();",
+ format("#define A( \\\n"
+ " x) /* \\\n"
+ " a comment \\\n"
+ " inside */ \\\n"
+ " f();",
+ getLLVMStyleWithColumns(17)));
+}
+
+TEST_F(FormatTestComments, ParsesCommentsAdjacentToPPDirectives) {
+ EXPECT_EQ("namespace {}\n// Test\n#define A",
+ format("namespace {}\n // Test\n#define A"));
+ EXPECT_EQ("namespace {}\n/* Test */\n#define A",
+ format("namespace {}\n /* Test */\n#define A"));
+ EXPECT_EQ("namespace {}\n/* Test */ #define A",
+ format("namespace {}\n /* Test */ #define A"));
+}
+
+TEST_F(FormatTestComments, SplitsLongLinesInComments) {
+ EXPECT_EQ("/* This is a long\n"
+ " * comment that\n"
+ " * doesn't\n"
+ " * fit on one line.\n"
+ " */",
+ format("/* "
+ "This is a long "
+ "comment that "
+ "doesn't "
+ "fit on one line. */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ(
+ "/* a b c d\n"
+ " * e f g\n"
+ " * h i j k\n"
+ " */",
+ format("/* a b c d e f g h i j k */", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ(
+ "/* a b c d\n"
+ " * e f g\n"
+ " * h i j k\n"
+ " */",
+ format("\\\n/* a b c d e f g h i j k */", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("/*\n"
+ "This is a long\n"
+ "comment that doesn't\n"
+ "fit on one line.\n"
+ "*/",
+ format("/*\n"
+ "This is a long "
+ "comment that doesn't "
+ "fit on one line. \n"
+ "*/",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ " * This is a long\n"
+ " * comment that\n"
+ " * doesn't fit on\n"
+ " * one line.\n"
+ " */",
+ format("/* \n"
+ " * This is a long "
+ " comment that "
+ " doesn't fit on "
+ " one line. \n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ " * This_is_a_comment_with_words_that_dont_fit_on_one_line\n"
+ " * so_it_should_be_broken\n"
+ " * wherever_a_space_occurs\n"
+ " */",
+ format("/*\n"
+ " * This_is_a_comment_with_words_that_dont_fit_on_one_line "
+ " so_it_should_be_broken "
+ " wherever_a_space_occurs \n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ " * This_comment_can_not_be_broken_into_lines\n"
+ " */",
+ format("/*\n"
+ " * This_comment_can_not_be_broken_into_lines\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("{\n"
+ " /*\n"
+ " This is another\n"
+ " long comment that\n"
+ " doesn't fit on one\n"
+ " line 1234567890\n"
+ " */\n"
+ "}",
+ format("{\n"
+ "/*\n"
+ "This is another "
+ " long comment that "
+ " doesn't fit on one"
+ " line 1234567890\n"
+ "*/\n"
+ "}",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("{\n"
+ " /*\n"
+ " * This i s\n"
+ " * another comment\n"
+ " * t hat doesn' t\n"
+ " * fit on one l i\n"
+ " * n e\n"
+ " */\n"
+ "}",
+ format("{\n"
+ "/*\n"
+ " * This i s"
+ " another comment"
+ " t hat doesn' t"
+ " fit on one l i"
+ " n e\n"
+ " */\n"
+ "}",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ " * This is a long\n"
+ " * comment that\n"
+ " * doesn't fit on\n"
+ " * one line\n"
+ " */",
+ format(" /*\n"
+ " * This is a long comment that doesn't fit on one line\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("{\n"
+ " if (something) /* This is a\n"
+ " long\n"
+ " comment */\n"
+ " ;\n"
+ "}",
+ format("{\n"
+ " if (something) /* This is a long comment */\n"
+ " ;\n"
+ "}",
+ getLLVMStyleWithColumns(30)));
+
+ EXPECT_EQ("/* A comment before\n"
+ " * a macro\n"
+ " * definition */\n"
+ "#define a b",
+ format("/* A comment before a macro definition */\n"
+ "#define a b",
+ getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("/* some comment\n"
+ " * a comment that\n"
+ " * we break another\n"
+ " * comment we have\n"
+ " * to break a left\n"
+ " * comment\n"
+ " */",
+ format(" /* some comment\n"
+ " * a comment that we break\n"
+ " * another comment we have to break\n"
+ "* a left comment\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("/**\n"
+ " * multiline block\n"
+ " * comment\n"
+ " *\n"
+ " */",
+ format("/**\n"
+ " * multiline block comment\n"
+ " *\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("/*\n"
+ "\n"
+ "\n"
+ " */\n",
+ format(" /* \n"
+ " \n"
+ " \n"
+ " */\n"));
+
+ EXPECT_EQ("/* a a */",
+ format("/* a a */", getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("/* a a bc */",
+ format("/* a a bc */", getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("/* aaa aaa\n"
+ " * aaaaa */",
+ format("/* aaa aaa aaaaa */", getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("/* aaa aaa\n"
+ " * aaaaa */",
+ format("/* aaa aaa aaaaa */", getLLVMStyleWithColumns(15)));
+}
+
+TEST_F(FormatTestComments, SplitsLongLinesInCommentsInPreprocessor) {
+ EXPECT_EQ("#define X \\\n"
+ " /* \\\n"
+ " Test \\\n"
+ " Macro comment \\\n"
+ " with a long \\\n"
+ " line \\\n"
+ " */ \\\n"
+ " A + B",
+ format("#define X \\\n"
+ " /*\n"
+ " Test\n"
+ " Macro comment with a long line\n"
+ " */ \\\n"
+ " A + B",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("#define X \\\n"
+ " /* Macro comment \\\n"
+ " with a long \\\n"
+ " line */ \\\n"
+ " A + B",
+ format("#define X \\\n"
+ " /* Macro comment with a long\n"
+ " line */ \\\n"
+ " A + B",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("#define X \\\n"
+ " /* Macro comment \\\n"
+ " * with a long \\\n"
+ " * line */ \\\n"
+ " A + B",
+ format("#define X \\\n"
+ " /* Macro comment with a long line */ \\\n"
+ " A + B",
+ getLLVMStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestComments, CommentsInStaticInitializers) {
+ EXPECT_EQ(
+ "static SomeType type = {aaaaaaaaaaaaaaaaaaaa, /* comment */\n"
+ " aaaaaaaaaaaaaaaaaaaa /* comment */,\n"
+ " /* comment */ aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaa, // comment\n"
+ " aaaaaaaaaaaaaaaaaaaa};",
+ format("static SomeType type = { aaaaaaaaaaaaaaaaaaaa , /* comment */\n"
+ " aaaaaaaaaaaaaaaaaaaa /* comment */ ,\n"
+ " /* comment */ aaaaaaaaaaaaaaaaaaaa ,\n"
+ " aaaaaaaaaaaaaaaaaaaa , // comment\n"
+ " aaaaaaaaaaaaaaaaaaaa };"));
+ verifyFormat("static SomeType type = {aaaaaaaaaaa, // comment for aa...\n"
+ " bbbbbbbbbbb, ccccccccccc};");
+ verifyFormat("static SomeType type = {aaaaaaaaaaa,\n"
+ " // comment for bb....\n"
+ " bbbbbbbbbbb, ccccccccccc};");
+ verifyGoogleFormat(
+ "static SomeType type = {aaaaaaaaaaa, // comment for aa...\n"
+ " bbbbbbbbbbb, ccccccccccc};");
+ verifyGoogleFormat("static SomeType type = {aaaaaaaaaaa,\n"
+ " // comment for bb....\n"
+ " bbbbbbbbbbb, ccccccccccc};");
+
+ verifyFormat("S s = {{a, b, c}, // Group #1\n"
+ " {d, e, f}, // Group #2\n"
+ " {g, h, i}}; // Group #3");
+ verifyFormat("S s = {{// Group #1\n"
+ " a, b, c},\n"
+ " {// Group #2\n"
+ " d, e, f},\n"
+ " {// Group #3\n"
+ " g, h, i}};");
+
+ EXPECT_EQ("S s = {\n"
+ " // Some comment\n"
+ " a,\n"
+ "\n"
+ " // Comment after empty line\n"
+ " b}",
+ format("S s = {\n"
+ " // Some comment\n"
+ " a,\n"
+ " \n"
+ " // Comment after empty line\n"
+ " b\n"
+ "}"));
+ EXPECT_EQ("S s = {\n"
+ " /* Some comment */\n"
+ " a,\n"
+ "\n"
+ " /* Comment after empty line */\n"
+ " b}",
+ format("S s = {\n"
+ " /* Some comment */\n"
+ " a,\n"
+ " \n"
+ " /* Comment after empty line */\n"
+ " b\n"
+ "}"));
+ verifyFormat("const uint8_t aaaaaaaaaaaaaaaaaaaaaa[0] = {\n"
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
+ " 0x00, 0x00, 0x00, 0x00}; // comment\n");
+}
+
+TEST_F(FormatTestComments, LineCommentsAfterRightBrace) {
+ EXPECT_EQ("if (true) { // comment about branch\n"
+ " // comment about f\n"
+ " f();\n"
+ "}",
+ format("if (true) { // comment about branch\n"
+ " // comment about f\n"
+ " f();\n"
+ "}",
+ getLLVMStyleWithColumns(80)));
+ EXPECT_EQ("if (1) { // if line 1\n"
+ " // if line 2\n"
+ " // if line 3\n"
+ " // f line 1\n"
+ " // f line 2\n"
+ " f();\n"
+ "} else { // else line 1\n"
+ " // else line 2\n"
+ " // else line 3\n"
+ " // g line 1\n"
+ " g();\n"
+ "}",
+ format("if (1) { // if line 1\n"
+ " // if line 2\n"
+ " // if line 3\n"
+ " // f line 1\n"
+ " // f line 2\n"
+ " f();\n"
+ "} else { // else line 1\n"
+ " // else line 2\n"
+ " // else line 3\n"
+ " // g line 1\n"
+ " g();\n"
+ "}"));
+ EXPECT_EQ("do { // line 1\n"
+ " // line 2\n"
+ " // line 3\n"
+ " f();\n"
+ "} while (true);",
+ format("do { // line 1\n"
+ " // line 2\n"
+ " // line 3\n"
+ " f();\n"
+ "} while (true);",
+ getLLVMStyleWithColumns(80)));
+ EXPECT_EQ("while (a < b) { // line 1\n"
+ " // line 2\n"
+ " // line 3\n"
+ " f();\n"
+ "}",
+ format("while (a < b) {// line 1\n"
+ " // line 2\n"
+ " // line 3\n"
+ " f();\n"
+ "}",
+ getLLVMStyleWithColumns(80)));
+}
+
+TEST_F(FormatTestComments, ReflowsComments) {
+ // Break a long line and reflow with the full next line.
+ EXPECT_EQ("// long long long\n"
+ "// long long",
+ format("// long long long long\n"
+ "// long",
+ getLLVMStyleWithColumns(20)));
+
+ // Keep the trailing newline while reflowing.
+ EXPECT_EQ("// long long long\n"
+ "// long long\n",
+ format("// long long long long\n"
+ "// long\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Break a long line and reflow with a part of the next line.
+ EXPECT_EQ("// long long long\n"
+ "// long long\n"
+ "// long_long",
+ format("// long long long long\n"
+ "// long long_long",
+ getLLVMStyleWithColumns(20)));
+
+ // Break but do not reflow if the first word from the next line is too long.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// long_long_long\n",
+ format("// long long long long\n"
+ "// long_long_long\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't break or reflow short lines.
+ verifyFormat("// long\n"
+ "// long long long lo\n"
+ "// long long long lo\n"
+ "// long",
+ getLLVMStyleWithColumns(20));
+
+ // Keep prefixes and decorations while reflowing.
+ EXPECT_EQ("/// long long long\n"
+ "/// long long\n",
+ format("/// long long long long\n"
+ "/// long\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("//! long long long\n"
+ "//! long long\n",
+ format("//! long long long long\n"
+ "//! long\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/* long long long\n"
+ " * long long */",
+ format("/* long long long long\n"
+ " * long */",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't bring leading whitespace up while reflowing.
+ EXPECT_EQ("/* long long long\n"
+ " * long long long\n"
+ " */",
+ format("/* long long long long\n"
+ " * long long\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow the last line of a block comment with its trailing '*/'.
+ EXPECT_EQ("/* long long long\n"
+ " long long */",
+ format("/* long long long long\n"
+ " long */",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow two short lines; keep the postfix of the last one.
+ EXPECT_EQ("/* long long long\n"
+ " * long long long */",
+ format("/* long long long long\n"
+ " * long\n"
+ " * long */",
+ getLLVMStyleWithColumns(20)));
+
+ // Put the postfix of the last short reflow line on a newline if it doesn't
+ // fit.
+ EXPECT_EQ("/* long long long\n"
+ " * long long longg\n"
+ " */",
+ format("/* long long long long\n"
+ " * long\n"
+ " * longg */",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow lines with leading whitespace.
+ EXPECT_EQ("{\n"
+ " /*\n"
+ " * long long long\n"
+ " * long long long\n"
+ " * long long long\n"
+ " */\n"
+ "}",
+ format("{\n"
+ "/*\n"
+ " * long long long long\n"
+ " * long\n"
+ " * long long long long\n"
+ " */\n"
+ "}",
+ getLLVMStyleWithColumns(20)));
+
+ // Break single line block comments that are first in the line with ' *'
+ // decoration.
+ EXPECT_EQ("/* long long long\n"
+ " * long */",
+ format("/* long long long long */", getLLVMStyleWithColumns(20)));
+
+ // Break single line block comment that are not first in the line with ' '
+ // decoration.
+ EXPECT_EQ("int i; /* long long\n"
+ " long */",
+ format("int i; /* long long long */", getLLVMStyleWithColumns(20)));
+
+ // Reflow a line that goes just over the column limit.
+ EXPECT_EQ("// long long long\n"
+ "// lon long",
+ format("// long long long lon\n"
+ "// long",
+ getLLVMStyleWithColumns(20)));
+
+ // Stop reflowing if the next line has a different indentation than the
+ // previous line.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// long long\n"
+ "// long",
+ format("// long long long long\n"
+ "// long long\n"
+ "// long",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow into the last part of a really long line that has been broken into
+ // multiple lines.
+ EXPECT_EQ("// long long long\n"
+ "// long long long\n"
+ "// long long long\n",
+ format("// long long long long long long long long\n"
+ "// long\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Break the first line, then reflow the beginning of the second and third
+ // line up.
+ EXPECT_EQ("// long long long\n"
+ "// lon1 lon2 lon2\n"
+ "// lon2 lon3 lon3",
+ format("// long long long lon1\n"
+ "// lon2 lon2 lon2\n"
+ "// lon3 lon3",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow the beginning of the second line, then break the rest.
+ EXPECT_EQ("// long long long\n"
+ "// lon1 lon2 lon2\n"
+ "// lon2 lon2 lon2\n"
+ "// lon3",
+ format("// long long long lon1\n"
+ "// lon2 lon2 lon2 lon2 lon2 lon3",
+ getLLVMStyleWithColumns(20)));
+
+ // Shrink the first line, then reflow the second line up.
+ EXPECT_EQ("// long long long", format("// long long\n"
+ "// long",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't shrink leading whitespace.
+ EXPECT_EQ("int i; /// a",
+ format("int i; /// a", getLLVMStyleWithColumns(20)));
+
+ // Shrink trailing whitespace if there is no postfix and reflow.
+ EXPECT_EQ("// long long long\n"
+ "// long long",
+ format("// long long long long \n"
+ "// long",
+ getLLVMStyleWithColumns(20)));
+
+ // Shrink trailing whitespace to a single one if there is postfix.
+ EXPECT_EQ("/* long long long */",
+ format("/* long long long */", getLLVMStyleWithColumns(20)));
+
+ // Break a block comment postfix if exceeding the line limit.
+ EXPECT_EQ("/* long\n"
+ " */",
+ format("/* long */", getLLVMStyleWithColumns(20)));
+
+ // Reflow indented comments.
+ EXPECT_EQ("{\n"
+ " // long long long\n"
+ " // long long\n"
+ " int i; /* long lon\n"
+ " g long\n"
+ " */\n"
+ "}",
+ format("{\n"
+ " // long long long long\n"
+ " // long\n"
+ " int i; /* long lon g\n"
+ " long */\n"
+ "}",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't realign trailing comments after reflow has happened.
+ EXPECT_EQ("// long long long\n"
+ "// long long\n"
+ "long i; // long",
+ format("// long long long long\n"
+ "// long\n"
+ "long i; // long",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// long long long\n"
+ "// longng long long\n"
+ "// long lo",
+ format("// long long long longng\n"
+ "// long long long\n"
+ "// lo",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow lines after a broken line.
+ EXPECT_EQ("int a; // Trailing\n"
+ " // comment on\n"
+ " // 2 or 3\n"
+ " // lines.\n",
+ format("int a; // Trailing comment\n"
+ " // on 2\n"
+ " // or 3\n"
+ " // lines.\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/// This long line\n"
+ "/// gets reflown.\n",
+ format("/// This long line gets\n"
+ "/// reflown.\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("//! This long line\n"
+ "//! gets reflown.\n",
+ format(" //! This long line gets\n"
+ " //! reflown.\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/* This long line\n"
+ " * gets reflown.\n"
+ " */\n",
+ format("/* This long line gets\n"
+ " * reflown.\n"
+ " */\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow after indentation makes a line too long.
+ EXPECT_EQ("{\n"
+ " // long long long\n"
+ " // lo long\n"
+ "}\n",
+ format("{\n"
+ "// long long long lo\n"
+ "// long\n"
+ "}\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Break and reflow multiple lines.
+ EXPECT_EQ("/*\n"
+ " * Reflow the end of\n"
+ " * line by 11 22 33\n"
+ " * 4.\n"
+ " */\n",
+ format("/*\n"
+ " * Reflow the end of line\n"
+ " * by\n"
+ " * 11\n"
+ " * 22\n"
+ " * 33\n"
+ " * 4.\n"
+ " */\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/// First line gets\n"
+ "/// broken. Second\n"
+ "/// line gets\n"
+ "/// reflown and\n"
+ "/// broken. Third\n"
+ "/// gets reflown.\n",
+ format("/// First line gets broken.\n"
+ "/// Second line gets reflown and broken.\n"
+ "/// Third gets reflown.\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("int i; // first long\n"
+ " // long snd\n"
+ " // long.\n",
+ format("int i; // first long long\n"
+ " // snd long.\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("{\n"
+ " // first long line\n"
+ " // line second\n"
+ " // long line line\n"
+ " // third long line\n"
+ " // line\n"
+ "}\n",
+ format("{\n"
+ " // first long line line\n"
+ " // second long line line\n"
+ " // third long line line\n"
+ "}\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("int i; /* first line\n"
+ " * second\n"
+ " * line third\n"
+ " * line\n"
+ " */",
+ format("int i; /* first line\n"
+ " * second line\n"
+ " * third line\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow the last two lines of a section that starts with a line having
+ // different indentation.
+ EXPECT_EQ(
+ "// long\n"
+ "// long long long\n"
+ "// long long",
+ format("// long\n"
+ "// long long long long\n"
+ "// long",
+ getLLVMStyleWithColumns(20)));
+
+ // Keep the block comment endling '*/' while reflowing.
+ EXPECT_EQ("/* Long long long\n"
+ " * line short */\n",
+ format("/* Long long long line\n"
+ " * short */\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow between separate blocks of comments.
+ EXPECT_EQ("/* First comment\n"
+ " * block will */\n"
+ "/* Snd\n"
+ " */\n",
+ format("/* First comment block\n"
+ " * will */\n"
+ "/* Snd\n"
+ " */\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow across blank comment lines.
+ EXPECT_EQ("int i; // This long\n"
+ " // line gets\n"
+ " // broken.\n"
+ " //\n"
+ " // keep.\n",
+ format("int i; // This long line gets broken.\n"
+ " // \n"
+ " // keep.\n",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("{\n"
+ " /// long long long\n"
+ " /// long long\n"
+ " ///\n"
+ " /// long\n"
+ "}",
+ format("{\n"
+ " /// long long long long\n"
+ " /// long\n"
+ " ///\n"
+ " /// long\n"
+ "}",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("//! long long long\n"
+ "//! long\n"
+ "\n"
+ "//! long",
+ format("//! long long long long\n"
+ "\n"
+ "//! long",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/* long long long\n"
+ " long\n"
+ "\n"
+ " long */",
+ format("/* long long long long\n"
+ "\n"
+ " long */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/* long long long\n"
+ " * long\n"
+ " *\n"
+ " * long */",
+ format("/* long long long long\n"
+ " *\n"
+ " * long */",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow lines having content that is a single character.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// l",
+ format("// long long long long\n"
+ "// l",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow lines starting with two punctuation characters.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// ... --- ...",
+ format(
+ "// long long long long\n"
+ "// ... --- ...",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow lines starting with '@'.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// @param arg",
+ format("// long long long long\n"
+ "// @param arg",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow lines starting with 'TODO'.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// TODO: long",
+ format("// long long long long\n"
+ "// TODO: long",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow lines starting with 'FIXME'.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// FIXME: long",
+ format("// long long long long\n"
+ "// FIXME: long",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow lines starting with 'XXX'.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// XXX: long",
+ format("// long long long long\n"
+ "// XXX: long",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow comment pragmas.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// IWYU pragma:",
+ format("// long long long long\n"
+ "// IWYU pragma:",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/* long long long\n"
+ " * long\n"
+ " * IWYU pragma:\n"
+ " */",
+ format("/* long long long long\n"
+ " * IWYU pragma:\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+
+ // Reflow lines that have a non-punctuation character among their first 2
+ // characters.
+ EXPECT_EQ("// long long long\n"
+ "// long 'long'",
+ format(
+ "// long long long long\n"
+ "// 'long'",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow between separate blocks of comments.
+ EXPECT_EQ("/* First comment\n"
+ " * block will */\n"
+ "/* Snd\n"
+ " */\n",
+ format("/* First comment block\n"
+ " * will */\n"
+ "/* Snd\n"
+ " */\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow lines having different indentation.
+ EXPECT_EQ("// long long long\n"
+ "// long\n"
+ "// long",
+ format("// long long long long\n"
+ "// long",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't break or reflow after implicit string literals.
+ verifyFormat("#include <t> // l l l\n"
+ " // l",
+ getLLVMStyleWithColumns(20));
+
+ // Don't break or reflow comments on import lines.
+ EXPECT_EQ("#include \"t\" /* l l l\n"
+ " * l */",
+ format("#include \"t\" /* l l l\n"
+ " * l */",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow between different trailing comment sections.
+ EXPECT_EQ("int i; // long long\n"
+ " // long\n"
+ "int j; // long long\n"
+ " // long\n",
+ format("int i; // long long long\n"
+ "int j; // long long long\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Don't reflow if the first word on the next line is longer than the
+ // available space at current line.
+ EXPECT_EQ("int i; // trigger\n"
+ " // reflow\n"
+ " // longsec\n",
+ format("int i; // trigger reflow\n"
+ " // longsec\n",
+ getLLVMStyleWithColumns(20)));
+
+ // Keep empty comment lines.
+ EXPECT_EQ("/**/", format(" /**/", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/* */", format(" /* */", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/* */", format(" /* */", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("//", format(" // ", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("///", format(" /// ", getLLVMStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestComments, IgnoresIf0Contents) {
+ EXPECT_EQ("#if 0\n"
+ "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n"
+ "#endif\n"
+ "void f() {}",
+ format("#if 0\n"
+ "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n"
+ "#endif\n"
+ "void f( ) { }"));
+ EXPECT_EQ("#if false\n"
+ "void f( ) { }\n"
+ "#endif\n"
+ "void g() {}\n",
+ format("#if false\n"
+ "void f( ) { }\n"
+ "#endif\n"
+ "void g( ) { }\n"));
+ EXPECT_EQ("enum E {\n"
+ " One,\n"
+ " Two,\n"
+ "#if 0\n"
+ "Three,\n"
+ " Four,\n"
+ "#endif\n"
+ " Five\n"
+ "};",
+ format("enum E {\n"
+ " One,Two,\n"
+ "#if 0\n"
+ "Three,\n"
+ " Four,\n"
+ "#endif\n"
+ " Five};"));
+ EXPECT_EQ("enum F {\n"
+ " One,\n"
+ "#if 1\n"
+ " Two,\n"
+ "#if 0\n"
+ "Three,\n"
+ " Four,\n"
+ "#endif\n"
+ " Five\n"
+ "#endif\n"
+ "};",
+ format("enum F {\n"
+ "One,\n"
+ "#if 1\n"
+ "Two,\n"
+ "#if 0\n"
+ "Three,\n"
+ " Four,\n"
+ "#endif\n"
+ "Five\n"
+ "#endif\n"
+ "};"));
+ EXPECT_EQ("enum G {\n"
+ " One,\n"
+ "#if 0\n"
+ "Two,\n"
+ "#else\n"
+ " Three,\n"
+ "#endif\n"
+ " Four\n"
+ "};",
+ format("enum G {\n"
+ "One,\n"
+ "#if 0\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "Four\n"
+ "};"));
+ EXPECT_EQ("enum H {\n"
+ " One,\n"
+ "#if 0\n"
+ "#ifdef Q\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "#endif\n"
+ " Four\n"
+ "};",
+ format("enum H {\n"
+ "One,\n"
+ "#if 0\n"
+ "#ifdef Q\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "#endif\n"
+ "Four\n"
+ "};"));
+ EXPECT_EQ("enum I {\n"
+ " One,\n"
+ "#if /* test */ 0 || 1\n"
+ "Two,\n"
+ "Three,\n"
+ "#endif\n"
+ " Four\n"
+ "};",
+ format("enum I {\n"
+ "One,\n"
+ "#if /* test */ 0 || 1\n"
+ "Two,\n"
+ "Three,\n"
+ "#endif\n"
+ "Four\n"
+ "};"));
+ EXPECT_EQ("enum J {\n"
+ " One,\n"
+ "#if 0\n"
+ "#if 0\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "Four,\n"
+ "#endif\n"
+ " Five\n"
+ "};",
+ format("enum J {\n"
+ "One,\n"
+ "#if 0\n"
+ "#if 0\n"
+ "Two,\n"
+ "#else\n"
+ "Three,\n"
+ "#endif\n"
+ "Four,\n"
+ "#endif\n"
+ "Five\n"
+ "};"));
+
+ // Ignore stuff in SWIG-blocks.
+ EXPECT_EQ("#ifdef SWIG\n"
+ "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n"
+ "#endif\n"
+ "void f() {}",
+ format("#ifdef SWIG\n"
+ "}{)(&*(^%%#%@! fsadj f;ldjs ,:;| <<<>>>][)(][\n"
+ "#endif\n"
+ "void f( ) { }"));
+ EXPECT_EQ("#ifndef SWIG\n"
+ "void f() {}\n"
+ "#endif",
+ format("#ifndef SWIG\n"
+ "void f( ) { }\n"
+ "#endif"));
+}
+
+TEST_F(FormatTestComments, DontCrashOnBlockComments) {
+ EXPECT_EQ(
+ "int xxxxxxxxx; /* "
+ "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\n"
+ "zzzzzz\n"
+ "0*/",
+ format("int xxxxxxxxx; /* "
+ "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy zzzzzz\n"
+ "0*/"));
+}
+
+TEST_F(FormatTestComments, BlockCommentsInControlLoops) {
+ verifyFormat("if (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("if (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "} /* another comment */ else /* comment #3 */ {\n"
+ " g();\n"
+ "}");
+ verifyFormat("while (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("for (;;) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("do /* a comment in a strange place */ {\n"
+ " f();\n"
+ "} /* another comment */ while (0);");
+}
+
+TEST_F(FormatTestComments, BlockComments) {
+ EXPECT_EQ("/* */ /* */ /* */\n/* */ /* */ /* */",
+ format("/* *//* */ /* */\n/* *//* */ /* */"));
+ EXPECT_EQ("/* */ a /* */ b;", format(" /* */ a/* */ b;"));
+ EXPECT_EQ("#define A /*123*/ \\\n"
+ " b\n"
+ "/* */\n"
+ "someCall(\n"
+ " parameter);",
+ format("#define A /*123*/ b\n"
+ "/* */\n"
+ "someCall(parameter);",
+ getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ("#define A\n"
+ "/* */ someCall(\n"
+ " parameter);",
+ format("#define A\n"
+ "/* */someCall(parameter);",
+ getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("/*\n**\n*/", format("/*\n**\n*/"));
+ EXPECT_EQ("/*\n"
+ " *\n"
+ " * aaaaaa\n"
+ " * aaaaaa\n"
+ " */",
+ format("/*\n"
+ "*\n"
+ " * aaaaaa aaaaaa\n"
+ "*/",
+ getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("/*\n"
+ "**\n"
+ "* aaaaaa\n"
+ "*aaaaaa\n"
+ "*/",
+ format("/*\n"
+ "**\n"
+ "* aaaaaa aaaaaa\n"
+ "*/",
+ getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("int aaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " /* line 1\n"
+ " bbbbbbbbbbbb */\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
+ format("int aaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " /* line 1\n"
+ " bbbbbbbbbbbb */ bbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
+ getLLVMStyleWithColumns(50)));
+
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ EXPECT_EQ("someFunction(1, /* comment 1 */\n"
+ " 2, /* comment 2 */\n"
+ " 3, /* comment 3 */\n"
+ " aaaa,\n"
+ " bbbb);",
+ format("someFunction (1, /* comment 1 */\n"
+ " 2, /* comment 2 */ \n"
+ " 3, /* comment 3 */\n"
+ "aaaa, bbbb );",
+ NoBinPacking));
+ verifyFormat(
+ "bool aaaaaaaaaaaaa = /* comment: */ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ EXPECT_EQ(
+ "bool aaaaaaaaaaaaa = /* trailing comment */\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ format(
+ "bool aaaaaaaaaaaaa = /* trailing comment */\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa||aaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaa;"));
+ EXPECT_EQ(
+ "int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; /* comment */\n"
+ "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; /* comment */\n"
+ "int cccccccccccccccccccccccccccccc; /* comment */\n",
+ format("int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; /* comment */\n"
+ "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; /* comment */\n"
+ "int cccccccccccccccccccccccccccccc; /* comment */\n"));
+
+ verifyFormat("void f(int * /* unused */) {}");
+
+ EXPECT_EQ("/*\n"
+ " **\n"
+ " */",
+ format("/*\n"
+ " **\n"
+ " */"));
+ EXPECT_EQ("/*\n"
+ " *q\n"
+ " */",
+ format("/*\n"
+ " *q\n"
+ " */"));
+ EXPECT_EQ("/*\n"
+ " * q\n"
+ " */",
+ format("/*\n"
+ " * q\n"
+ " */"));
+ EXPECT_EQ("/*\n"
+ " **/",
+ format("/*\n"
+ " **/"));
+ EXPECT_EQ("/*\n"
+ " ***/",
+ format("/*\n"
+ " ***/"));
+}
+
+TEST_F(FormatTestComments, BlockCommentsInMacros) {
+ EXPECT_EQ("#define A \\\n"
+ " { \\\n"
+ " /* one line */ \\\n"
+ " someCall();",
+ format("#define A { \\\n"
+ " /* one line */ \\\n"
+ " someCall();",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("#define A \\\n"
+ " { \\\n"
+ " /* previous */ \\\n"
+ " /* one line */ \\\n"
+ " someCall();",
+ format("#define A { \\\n"
+ " /* previous */ \\\n"
+ " /* one line */ \\\n"
+ " someCall();",
+ getLLVMStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestComments, BlockCommentsAtEndOfLine) {
+ EXPECT_EQ("a = {\n"
+ " 1111 /* */\n"
+ "};",
+ format("a = {1111 /* */\n"
+ "};",
+ getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("a = {\n"
+ " 1111 /* */\n"
+ "};",
+ format("a = {1111 /* */\n"
+ "};",
+ getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("a = {\n"
+ " 1111 /* a\n"
+ " */\n"
+ "};",
+ format("a = {1111 /* a */\n"
+ "};",
+ getLLVMStyleWithColumns(15)));
+}
+
+TEST_F(FormatTestComments, IndentLineCommentsInStartOfBlockAtEndOfFile) {
+ verifyFormat("{\n"
+ " // a\n"
+ " // b");
+}
+
+TEST_F(FormatTestComments, AlignTrailingComments) {
+ EXPECT_EQ("#define MACRO(V) \\\n"
+ " V(Rt2) /* one more char */ \\\n"
+ " V(Rs) /* than here */ \\\n"
+ "/* comment 3 */\n",
+ format("#define MACRO(V)\\\n"
+ "V(Rt2) /* one more char */ \\\n"
+ "V(Rs) /* than here */ \\\n"
+ "/* comment 3 */ \\\n",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("int i = f(abc, // line 1\n"
+ " d, // line 2\n"
+ " // line 3\n"
+ " b);",
+ format("int i = f(abc, // line 1\n"
+ " d, // line 2\n"
+ " // line 3\n"
+ " b);",
+ getLLVMStyleWithColumns(40)));
+
+ // Align newly broken trailing comments.
+ EXPECT_EQ("int ab; // line\n"
+ "int a; // long\n"
+ " // long\n",
+ format("int ab; // line\n"
+ "int a; // long long\n",
+ getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("int ab; // line\n"
+ "int a; // long\n"
+ " // long\n"
+ " // long",
+ format("int ab; // line\n"
+ "int a; // long long\n"
+ " // long",
+ getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("int ab; // line\n"
+ "int a; // long\n"
+ " // long\n"
+ "pt c; // long",
+ format("int ab; // line\n"
+ "int a; // long long\n"
+ "pt c; // long",
+ getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("int ab; // line\n"
+ "int a; // long\n"
+ " // long\n"
+ "\n"
+ "// long",
+ format("int ab; // line\n"
+ "int a; // long long\n"
+ "\n"
+ "// long",
+ getLLVMStyleWithColumns(15)));
+
+ // Align comment line sections aligned with the next token with the next
+ // token.
+ EXPECT_EQ("class A {\n"
+ "public: // public comment\n"
+ " // comment about a\n"
+ " int a;\n"
+ "};",
+ format("class A {\n"
+ "public: // public comment\n"
+ " // comment about a\n"
+ " int a;\n"
+ "};",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("class A {\n"
+ "public: // public comment 1\n"
+ " // public comment 2\n"
+ " // comment 1 about a\n"
+ " // comment 2 about a\n"
+ " int a;\n"
+ "};",
+ format("class A {\n"
+ "public: // public comment 1\n"
+ " // public comment 2\n"
+ " // comment 1 about a\n"
+ " // comment 2 about a\n"
+ " int a;\n"
+ "};",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("int f(int n) { // comment line 1 on f\n"
+ " // comment line 2 on f\n"
+ " // comment line 1 before return\n"
+ " // comment line 2 before return\n"
+ " return n; // comment line 1 on return\n"
+ " // comment line 2 on return\n"
+ " // comment line 1 after return\n"
+ "}",
+ format("int f(int n) { // comment line 1 on f\n"
+ " // comment line 2 on f\n"
+ " // comment line 1 before return\n"
+ " // comment line 2 before return\n"
+ " return n; // comment line 1 on return\n"
+ " // comment line 2 on return\n"
+ " // comment line 1 after return\n"
+ "}",
+ getLLVMStyleWithColumns(40)));
+ EXPECT_EQ("int f(int n) {\n"
+ " switch (n) { // comment line 1 on switch\n"
+ " // comment line 2 on switch\n"
+ " // comment line 1 before case 1\n"
+ " // comment line 2 before case 1\n"
+ " case 1: // comment line 1 on case 1\n"
+ " // comment line 2 on case 1\n"
+ " // comment line 1 before return 1\n"
+ " // comment line 2 before return 1\n"
+ " return 1; // comment line 1 on return 1\n"
+ " // comment line 2 on return 1\n"
+ " // comment line 1 before default\n"
+ " // comment line 2 before default\n"
+ " default: // comment line 1 on default\n"
+ " // comment line 2 on default\n"
+ " // comment line 1 before return 2\n"
+ " return 2 * f(n - 1); // comment line 1 on return 2\n"
+ " // comment line 2 on return 2\n"
+ " // comment line 1 after return\n"
+ " // comment line 2 after return\n"
+ " }\n"
+ "}",
+ format("int f(int n) {\n"
+ " switch (n) { // comment line 1 on switch\n"
+ " // comment line 2 on switch\n"
+ " // comment line 1 before case 1\n"
+ " // comment line 2 before case 1\n"
+ " case 1: // comment line 1 on case 1\n"
+ " // comment line 2 on case 1\n"
+ " // comment line 1 before return 1\n"
+ " // comment line 2 before return 1\n"
+ " return 1; // comment line 1 on return 1\n"
+ " // comment line 2 on return 1\n"
+ " // comment line 1 before default\n"
+ " // comment line 2 before default\n"
+ " default: // comment line 1 on default\n"
+ " // comment line 2 on default\n"
+ " // comment line 1 before return 2\n"
+ " return 2 * f(n - 1); // comment line 1 on return 2\n"
+ " // comment line 2 on return 2\n"
+ " // comment line 1 after return\n"
+ " // comment line 2 after return\n"
+ " }\n"
+ "}",
+ getLLVMStyleWithColumns(80)));
+
+ // If all the lines in a sequence of line comments are aligned with the next
+ // token, the first line belongs to the previous token and the other lines
+ // belong to the next token.
+ EXPECT_EQ("int a; // line about a\n"
+ "long b;",
+ format("int a; // line about a\n"
+ " long b;",
+ getLLVMStyleWithColumns(80)));
+ EXPECT_EQ("int a; // line about a\n"
+ "// line about b\n"
+ "long b;",
+ format("int a; // line about a\n"
+ " // line about b\n"
+ " long b;",
+ getLLVMStyleWithColumns(80)));
+ EXPECT_EQ("int a; // line about a\n"
+ "// line 1 about b\n"
+ "// line 2 about b\n"
+ "long b;",
+ format("int a; // line about a\n"
+ " // line 1 about b\n"
+ " // line 2 about b\n"
+ " long b;",
+ getLLVMStyleWithColumns(80)));
+}
+
+TEST_F(FormatTestComments, AlignsBlockCommentDecorations) {
+ EXPECT_EQ("/*\n"
+ " */",
+ format("/*\n"
+ "*/", getLLVMStyle()));
+ EXPECT_EQ("/*\n"
+ " */",
+ format("/*\n"
+ " */", getLLVMStyle()));
+ EXPECT_EQ("/*\n"
+ " */",
+ format("/*\n"
+ " */", getLLVMStyle()));
+
+ // Align a single line.
+ EXPECT_EQ("/*\n"
+ " * line */",
+ format("/*\n"
+ "* line */",
+ getLLVMStyle()));
+ EXPECT_EQ("/*\n"
+ " * line */",
+ format("/*\n"
+ " * line */",
+ getLLVMStyle()));
+ EXPECT_EQ("/*\n"
+ " * line */",
+ format("/*\n"
+ " * line */",
+ getLLVMStyle()));
+ EXPECT_EQ("/*\n"
+ " * line */",
+ format("/*\n"
+ " * line */",
+ getLLVMStyle()));
+ EXPECT_EQ("/**\n"
+ " * line */",
+ format("/**\n"
+ "* line */",
+ getLLVMStyle()));
+ EXPECT_EQ("/**\n"
+ " * line */",
+ format("/**\n"
+ " * line */",
+ getLLVMStyle()));
+ EXPECT_EQ("/**\n"
+ " * line */",
+ format("/**\n"
+ " * line */",
+ getLLVMStyle()));
+ EXPECT_EQ("/**\n"
+ " * line */",
+ format("/**\n"
+ " * line */",
+ getLLVMStyle()));
+ EXPECT_EQ("/**\n"
+ " * line */",
+ format("/**\n"
+ " * line */",
+ getLLVMStyle()));
+
+ // Align the end '*/' after a line.
+ EXPECT_EQ("/*\n"
+ " * line\n"
+ " */",
+ format("/*\n"
+ "* line\n"
+ "*/", getLLVMStyle()));
+ EXPECT_EQ("/*\n"
+ " * line\n"
+ " */",
+ format("/*\n"
+ " * line\n"
+ " */", getLLVMStyle()));
+ EXPECT_EQ("/*\n"
+ " * line\n"
+ " */",
+ format("/*\n"
+ " * line\n"
+ " */", getLLVMStyle()));
+
+ // Align two lines.
+ EXPECT_EQ("/* line 1\n"
+ " * line 2 */",
+ format("/* line 1\n"
+ " * line 2 */",
+ getLLVMStyle()));
+ EXPECT_EQ("/* line 1\n"
+ " * line 2 */",
+ format("/* line 1\n"
+ "* line 2 */",
+ getLLVMStyle()));
+ EXPECT_EQ("/* line 1\n"
+ " * line 2 */",
+ format("/* line 1\n"
+ " * line 2 */",
+ getLLVMStyle()));
+ EXPECT_EQ("/* line 1\n"
+ " * line 2 */",
+ format("/* line 1\n"
+ " * line 2 */",
+ getLLVMStyle()));
+ EXPECT_EQ("/* line 1\n"
+ " * line 2 */",
+ format("/* line 1\n"
+ " * line 2 */",
+ getLLVMStyle()));
+ EXPECT_EQ("int i; /* line 1\n"
+ " * line 2 */",
+ format("int i; /* line 1\n"
+ "* line 2 */",
+ getLLVMStyle()));
+ EXPECT_EQ("int i; /* line 1\n"
+ " * line 2 */",
+ format("int i; /* line 1\n"
+ " * line 2 */",
+ getLLVMStyle()));
+ EXPECT_EQ("int i; /* line 1\n"
+ " * line 2 */",
+ format("int i; /* line 1\n"
+ " * line 2 */",
+ getLLVMStyle()));
+
+ // Align several lines.
+ EXPECT_EQ("/* line 1\n"
+ " * line 2\n"
+ " * line 3 */",
+ format("/* line 1\n"
+ " * line 2\n"
+ "* line 3 */",
+ getLLVMStyle()));
+ EXPECT_EQ("/* line 1\n"
+ " * line 2\n"
+ " * line 3 */",
+ format("/* line 1\n"
+ " * line 2\n"
+ "* line 3 */",
+ getLLVMStyle()));
+ EXPECT_EQ("/*\n"
+ "** line 1\n"
+ "** line 2\n"
+ "*/",
+ format("/*\n"
+ "** line 1\n"
+ " ** line 2\n"
+ "*/",
+ getLLVMStyle()));
+
+ // Align with different indent after the decorations.
+ EXPECT_EQ("/*\n"
+ " * line 1\n"
+ " * line 2\n"
+ " * line 3\n"
+ " * line 4\n"
+ " */",
+ format("/*\n"
+ "* line 1\n"
+ " * line 2\n"
+ " * line 3\n"
+ "* line 4\n"
+ "*/", getLLVMStyle()));
+
+ // Align empty or blank lines.
+ EXPECT_EQ("/**\n"
+ " *\n"
+ " *\n"
+ " *\n"
+ " */",
+ format("/**\n"
+ "* \n"
+ " * \n"
+ " *\n"
+ "*/", getLLVMStyle()));
+
+ // Align while breaking and reflowing.
+ EXPECT_EQ("/*\n"
+ " * long long long\n"
+ " * long long\n"
+ " *\n"
+ " * long */",
+ format("/*\n"
+ " * long long long long\n"
+ " * long\n"
+ " *\n"
+ "* long */",
+ getLLVMStyleWithColumns(20)));
+}
+} // end namespace
+} // end namespace format
+} // end namespace clang
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index 230717fe47cc..d8fa8e4b942c 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -132,6 +132,8 @@ TEST_F(FormatTestJS, ReservedWords) {
verifyFormat("x.interface = 1;");
verifyFormat("x.for = 1;");
verifyFormat("x.of() = 1;");
+ verifyFormat("of(null);");
+ verifyFormat("import {of} from 'x';");
verifyFormat("x.in() = 1;");
verifyFormat("x.let() = 1;");
verifyFormat("x.var() = 1;");
@@ -167,6 +169,8 @@ TEST_F(FormatTestJS, ReservedWordsMethods) {
TEST_F(FormatTestJS, CppKeywords) {
// Make sure we don't mess stuff up because of C++ keywords.
verifyFormat("return operator && (aa);");
+ // .. or QT ones.
+ verifyFormat("slots: Slot[];");
}
TEST_F(FormatTestJS, ES6DestructuringAssignment) {
@@ -240,6 +244,18 @@ TEST_F(FormatTestJS, ContainerLiterals) {
"};");
verifyFormat("var x = {y: (a) => a};");
+ // Methods in object literals.
+ verifyFormat("var x = {\n"
+ " y(a: string): number {\n"
+ " return a;\n"
+ " }\n"
+ "};");
+ verifyFormat("var x = {\n"
+ " y(a: string) {\n"
+ " return a;\n"
+ " }\n"
+ "};");
+
// Computed keys.
verifyFormat("var x = {[a]: 1, b: 2, [c]: 3};");
verifyFormat("var x = {\n"
@@ -266,6 +282,11 @@ TEST_F(FormatTestJS, ContainerLiterals) {
" aaa,\n"
" aaa,\n"
"};");
+ verifyFormat("return {\n"
+ " a,\n"
+ " b: 'b',\n"
+ " c,\n"
+ "};");
}
TEST_F(FormatTestJS, MethodsInObjectLiterals) {
@@ -451,6 +472,8 @@ TEST_F(FormatTestJS, AsyncFunctions) {
verifyFormat("export async function f() {\n"
" return fetch(x);\n"
"}");
+ verifyFormat("let x = async () => f();");
+ verifyFormat("let x = async();");
verifyFormat("class X {\n"
" async asyncMethod() {\n"
" return fetch(1);\n"
@@ -497,6 +520,11 @@ TEST_F(FormatTestJS, ArrayLiterals) {
" [];");
verifyFormat("someFunction([], {a: a});");
+
+ verifyFormat("var string = [\n"
+ " 'aaaaaa',\n"
+ " 'bbbbbb',\n"
+ "].join('+');");
}
TEST_F(FormatTestJS, ColumnLayoutForArrayLiterals) {
@@ -587,6 +615,11 @@ TEST_F(FormatTestJS, FunctionLiterals) {
" doSomething();\n"
"}, this));");
+ verifyFormat("SomeFunction(function() {\n"
+ " foo();\n"
+ " bar();\n"
+ "}.bind(this));");
+
// FIXME: This is bad, we should be wrapping before "function() {".
verifyFormat("someFunction(function() {\n"
" doSomething(); // break\n"
@@ -858,13 +891,25 @@ TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
"return 1",
"a = null\n"
" return 1");
+ // Below "class Y {}" should ideally be on its own line.
verifyFormat(
"x = {\n"
" a: 1\n"
- "}\n"
- "class Y {}",
+ "} class Y {}",
" x = {a : 1}\n"
" class Y { }");
+ verifyFormat(
+ "if (x) {\n"
+ "}\n"
+ "return 1",
+ "if (x) {}\n"
+ " return 1");
+ verifyFormat(
+ "if (x) {\n"
+ "}\n"
+ "class X {}",
+ "if (x) {}\n"
+ " class X {}");
}
TEST_F(FormatTestJS, ImportExportASI) {
@@ -873,11 +918,17 @@ TEST_F(FormatTestJS, ImportExportASI) {
"export function z() {}",
"import {x} from 'y'\n"
" export function z() {}");
+ // Below "class Y {}" should ideally be on its own line.
verifyFormat(
- "export {x}\n"
- "class Y {}",
+ "export {x} class Y {}",
" export {x}\n"
" class Y {\n}");
+ verifyFormat(
+ "if (x) {\n"
+ "}\n"
+ "export class Y {}",
+ "if ( x ) { }\n"
+ " export class Y {}");
}
TEST_F(FormatTestJS, ClosureStyleCasts) {
@@ -913,6 +964,7 @@ TEST_F(FormatTestJS, RegexLiteralClassification) {
verifyFormat("var x = a ? /abc/ : /abc/;");
verifyFormat("for (var i = 0; /abc/.test(s[i]); i++) {\n}");
verifyFormat("var x = !/abc/.test(y);");
+ verifyFormat("var x = foo()! / 10;");
verifyFormat("var x = a && /abc/.test(y);");
verifyFormat("var x = a || /abc/.test(y);");
verifyFormat("var x = a + /abc/.search(y);");
@@ -1018,6 +1070,15 @@ TEST_F(FormatTestJS, RegexLiteralExamples) {
verifyFormat("var regex = search.match(/(?:\?|&)times=([^?&]+)/i);");
}
+TEST_F(FormatTestJS, IgnoresMpegTS) {
+ std::string MpegTS(200, ' ');
+ MpegTS.replace(0, strlen("nearlyLooks + like + ts + code; "),
+ "nearlyLooks + like + ts + code; ");
+ MpegTS[0] = 0x47;
+ MpegTS[188] = 0x47;
+ verifyFormat(MpegTS, MpegTS);
+}
+
TEST_F(FormatTestJS, TypeAnnotations) {
verifyFormat("var x: string;");
verifyFormat("var x: {a: string; b: number;} = {};");
@@ -1045,6 +1106,9 @@ TEST_F(FormatTestJS, TypeAnnotations) {
verifyFormat("function someFunc(args: string[]):\n"
" {longReturnValue: string[]} {}",
getGoogleJSStyleWithColumns(60));
+ verifyFormat(
+ "var someValue = (v as aaaaaaaaaaaaaaaaaaaa<T>[])\n"
+ " .someFunction(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
}
TEST_F(FormatTestJS, UnionIntersectionTypes) {
@@ -1072,6 +1136,10 @@ TEST_F(FormatTestJS, ClassDeclarations) {
verifyFormat("class C {\n static x(): string {\n return 'asd';\n }\n}");
verifyFormat("class C extends P implements I {}");
verifyFormat("class C extends p.P implements i.I {}");
+ verifyFormat(
+ "x(class {\n"
+ " a(): A {}\n"
+ "});");
verifyFormat("class Test {\n"
" aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaa):\n"
" aaaaaaaaaaaaaaaaaaaaaa {}\n"
@@ -1164,6 +1232,20 @@ TEST_F(FormatTestJS, TypeAliases) {
"class C {}");
}
+TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {
+ const FormatStyle &Style = getGoogleJSStyleWithColumns(20);
+ verifyFormat("type LongTypeIsReallyUnreasonablyLong =\n"
+ " string;\n",
+ "type LongTypeIsReallyUnreasonablyLong = string;\n",
+ Style);
+ verifyFormat(
+ "interface AbstractStrategyFactoryProvider {\n"
+ " a: number\n"
+ "}\n",
+ "interface AbstractStrategyFactoryProvider { a: number }\n",
+ Style);
+}
+
TEST_F(FormatTestJS, Modules) {
verifyFormat("import SomeThing from 'some/module.js';");
verifyFormat("import {X, Y} from 'some/module.js';");
@@ -1351,6 +1433,62 @@ TEST_F(FormatTestJS, TemplateStrings) {
"var y;");
// Escaped dollar.
verifyFormat("var x = ` \\${foo}`;\n");
+
+ // The token stream can contain two string_literals in sequence, but that
+ // doesn't mean that they are implicitly concatenated in JavaScript.
+ verifyFormat("var f = `aaaa ${a ? 'a' : 'b'}`;");
+
+ // Ensure that scopes are appropriately set around evaluated expressions in
+ // template strings.
+ verifyFormat("var f = `aaaaaaaaaaaaa:${aaaaaaa.aaaaa} aaaaaaaa\n"
+ " aaaaaaaaaaaaa:${aaaaaaa.aaaaa} aaaaaaaa`;",
+ "var f = `aaaaaaaaaaaaa:${aaaaaaa. aaaaa} aaaaaaaa\n"
+ " aaaaaaaaaaaaa:${ aaaaaaa. aaaaa} aaaaaaaa`;");
+ verifyFormat("var x = someFunction(`${})`) //\n"
+ " .oooooooooooooooooon();");
+ verifyFormat("var x = someFunction(`${aaaa}${\n"
+ " aaaaa( //\n"
+ " aaaaa)\n"
+ " })`);");
+}
+
+TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
+ verifyFormat("var f = `aaaaaaaaaaaaaaaaaa: ${\n"
+ " aaaaa + //\n"
+ " bbbb\n"
+ " }`;",
+ "var f = `aaaaaaaaaaaaaaaaaa: ${aaaaa + //\n"
+ " bbbb}`;");
+ verifyFormat("var f = `\n"
+ " aaaaaaaaaaaaaaaaaa: ${\n"
+ " aaaaa + //\n"
+ " bbbb\n"
+ " }`;",
+ "var f = `\n"
+ " aaaaaaaaaaaaaaaaaa: ${ aaaaa + //\n"
+ " bbbb }`;");
+ verifyFormat("var f = `\n"
+ " aaaaaaaaaaaaaaaaaa: ${\n"
+ " someFunction(\n"
+ " aaaaa + //\n"
+ " bbbb)\n"
+ " }`;",
+ "var f = `\n"
+ " aaaaaaaaaaaaaaaaaa: ${someFunction (\n"
+ " aaaaa + //\n"
+ " bbbb)}`;");
+
+ // It might be preferable to wrap before "someFunction".
+ verifyFormat("var f = `\n"
+ " aaaaaaaaaaaaaaaaaa: ${someFunction({\n"
+ " aaaa: aaaaa,\n"
+ " bbbb: bbbbb,\n"
+ " })}`;",
+ "var f = `\n"
+ " aaaaaaaaaaaaaaaaaa: ${someFunction ({\n"
+ " aaaa: aaaaa,\n"
+ " bbbb: bbbbb,\n"
+ " })}`;");
}
TEST_F(FormatTestJS, TemplateStringASI) {
@@ -1387,6 +1525,9 @@ TEST_F(FormatTestJS, CastSyntax) {
verifyFormat("x = x as {a: string};");
verifyFormat("x = x as (string);");
verifyFormat("x = x! as (string);");
+ verifyFormat("var x = something.someFunction() as\n"
+ " something;",
+ getGoogleJSStyleWithColumns(40));
}
TEST_F(FormatTestJS, TypeArguments) {
@@ -1460,6 +1601,58 @@ TEST_F(FormatTestJS, JSDocAnnotations) {
" * @export {this.is.a.long.path.to.a.Type}\n"
" */",
getGoogleJSStyleWithColumns(20));
+ verifyFormat("/**\n"
+ " * @mods {this.is.a.long.path.to.a.Type}\n"
+ " */",
+ "/**\n"
+ " * @mods {this.is.a.long.path.to.a.Type}\n"
+ " */",
+ getGoogleJSStyleWithColumns(20));
+ verifyFormat("/**\n"
+ " * @param {this.is.a.long.path.to.a.Type}\n"
+ " */",
+ "/**\n"
+ " * @param {this.is.a.long.path.to.a.Type}\n"
+ " */",
+ getGoogleJSStyleWithColumns(20));
+ verifyFormat("/**\n"
+ " * @see http://very/very/long/url/is/long\n"
+ " */",
+ "/**\n"
+ " * @see http://very/very/long/url/is/long\n"
+ " */",
+ getGoogleJSStyleWithColumns(20));
+ verifyFormat(
+ "/**\n"
+ " * @param This is a\n"
+ " * long comment but\n"
+ " * no type\n"
+ " */",
+ "/**\n"
+ " * @param This is a long comment but no type\n"
+ " */",
+ getGoogleJSStyleWithColumns(20));
+ // Don't break @param line, but reindent it and reflow unrelated lines.
+ verifyFormat("{\n"
+ " /**\n"
+ " * long long long\n"
+ " * long\n"
+ " * @param {this.is.a.long.path.to.a.Type} a\n"
+ " * long long long\n"
+ " * long long\n"
+ " */\n"
+ " function f(a) {}\n"
+ "}",
+ "{\n"
+ "/**\n"
+ " * long long long long\n"
+ " * @param {this.is.a.long.path.to.a.Type} a\n"
+ " * long long long long\n"
+ " * long\n"
+ " */\n"
+ " function f(a) {}\n"
+ "}",
+ getGoogleJSStyleWithColumns(20));
}
TEST_F(FormatTestJS, RequoteStringsSingle) {
@@ -1532,6 +1725,12 @@ TEST_F(FormatTestJS, NonNullAssertionOperator) {
verifyFormat("let x = (foo)!;\n");
verifyFormat("let x = foo! - 1;\n");
verifyFormat("let x = {foo: 1}!;\n");
+ verifyFormat(
+ "let x = hello.foo()!\n"
+ " .foo()!\n"
+ " .foo()!\n"
+ " .foo()!;\n",
+ getGoogleJSStyleWithColumns(20));
}
TEST_F(FormatTestJS, Conditional) {
@@ -1548,6 +1747,5 @@ TEST_F(FormatTestJS, ImportComments) {
getGoogleJSStyleWithColumns(25));
verifyFormat("// taze: x from 'location'", getGoogleJSStyleWithColumns(10));
}
-
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestJava.cpp b/unittests/Format/FormatTestJava.cpp
index dfc3debc46e2..6e685f6703e1 100644
--- a/unittests/Format/FormatTestJava.cpp
+++ b/unittests/Format/FormatTestJava.cpp
@@ -225,6 +225,13 @@ TEST_F(FormatTestJava, EnumDeclarations) {
" }\n"
" };\n"
"}");
+ verifyFormat("public enum VeryLongEnum {\n"
+ " ENUM_WITH_MANY_PARAMETERS(\n"
+ " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\", \"bbbbbbbbbbbbbbbb\", "
+ "\"cccccccccccccccccccccccc\"),\n"
+ " SECOND_ENUM(\"a\", \"b\", \"c\");\n"
+ " private VeryLongEnum(String a, String b, String c) {}\n"
+ "}\n");
}
TEST_F(FormatTestJava, ArrayInitializers) {
@@ -515,5 +522,17 @@ TEST_F(FormatTestJava, AlignsBlockComments) {
" void f() {}"));
}
+TEST_F(FormatTestJava, RetainsLogicalShifts) {
+ verifyFormat("void f() {\n"
+ " int a = 1;\n"
+ " a >>>= 1;\n"
+ "}");
+ verifyFormat("void f() {\n"
+ " int a = 1;\n"
+ " a = a >>> 1;\n"
+ "}");
+}
+
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestObjC.cpp b/unittests/Format/FormatTestObjC.cpp
index 6a530f921e6d..680ff92f75e8 100644
--- a/unittests/Format/FormatTestObjC.cpp
+++ b/unittests/Format/FormatTestObjC.cpp
@@ -68,17 +68,21 @@ protected:
FormatStyle Style;
};
-TEST_F(FormatTestObjC, DetectsObjCInHeaders) {
- Style = getStyle("LLVM", "a.h", "none", "@interface\n"
- "- (id)init;");
- EXPECT_EQ(FormatStyle::LK_ObjC, Style.Language);
+TEST(FormatTestObjCStyle, DetectsObjCInHeaders) {
+ auto Style = getStyle("LLVM", "a.h", "none", "@interface\n"
+ "- (id)init;");
+ ASSERT_TRUE((bool)Style);
+ EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
+
Style = getStyle("LLVM", "a.h", "none", "@interface\n"
"+ (id)init;");
- EXPECT_EQ(FormatStyle::LK_ObjC, Style.Language);
+ ASSERT_TRUE((bool)Style);
+ EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
// No recognizable ObjC.
Style = getStyle("LLVM", "a.h", "none", "void f() {}");
- EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language);
+ ASSERT_TRUE((bool)Style);
+ EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
}
TEST_F(FormatTestObjC, FormatObjCTryCatch) {
diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp
index 6881af4361cf..d174c65a1f32 100644
--- a/unittests/Format/FormatTestProto.cpp
+++ b/unittests/Format/FormatTestProto.cpp
@@ -135,6 +135,16 @@ TEST_F(FormatTestProto, MessageFieldAttributes) {
" key: 'a' //\n"
" }\n"
"];");
+ verifyFormat("optional string test = 1 [default =\n"
+ " \"test\"\n"
+ " \"test\"];");
+ verifyFormat("optional Aaaaaaaa aaaaaaaa = 12 [\n"
+ " (aaa) = aaaa,\n"
+ " (bbbbbbbbbbbbbbbbbbbbbbbbbb) = {\n"
+ " aaaaaaaaaaaaaaaaa: true,\n"
+ " aaaaaaaaaaaaaaaa: true\n"
+ " }\n"
+ "];");
}
TEST_F(FormatTestProto, DoesntWrapFileOptions) {
diff --git a/unittests/Format/FormatTestSelective.cpp b/unittests/Format/FormatTestSelective.cpp
index 2bc60fd1e0d3..367dbafcaf4c 100644
--- a/unittests/Format/FormatTestSelective.cpp
+++ b/unittests/Format/FormatTestSelective.cpp
@@ -111,13 +111,19 @@ TEST_F(FormatTestSelective, FormatsCommentsLocally) {
format("int a; // comment\n"
"int b; // comment",
0, 0));
- EXPECT_EQ("int a; // comment\n"
- " // line 2\n"
+ EXPECT_EQ("int a; // comment\n"
+ " // line 2\n"
"int b;",
format("int a; // comment\n"
" // line 2\n"
"int b;",
28, 0));
+ EXPECT_EQ("int a; // comment\n"
+ "// comment 2\n"
+ "int b;",
+ format("int a; // comment\n"
+ "// comment 2\n"
+ "int b;", 28, 0));
EXPECT_EQ("int aaaaaa; // comment\n"
"int b;\n"
"int c; // unrelated comment",
diff --git a/unittests/Format/NamespaceEndCommentsFixerTest.cpp b/unittests/Format/NamespaceEndCommentsFixerTest.cpp
new file mode 100644
index 000000000000..912638f45652
--- /dev/null
+++ b/unittests/Format/NamespaceEndCommentsFixerTest.cpp
@@ -0,0 +1,602 @@
+//===- NamespaceEndCommentsFixerTest.cpp - Formatting unit tests ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Format/Format.h"
+
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "namespace-end-comments-fixer-test"
+
+namespace clang {
+namespace format {
+namespace {
+
+class NamespaceEndCommentsFixerTest : public ::testing::Test {
+protected:
+ std::string
+ fixNamespaceEndComments(llvm::StringRef Code,
+ std::vector<tooling::Range> Ranges,
+ const FormatStyle &Style = getLLVMStyle()) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ tooling::Replacements Replaces =
+ clang::format::fixNamespaceEndComments(Style, Code, Ranges, "<stdin>");
+ auto Result = applyAllReplacements(Code, Replaces);
+ EXPECT_TRUE(static_cast<bool>(Result));
+ DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+ return *Result;
+ }
+
+ std::string
+ fixNamespaceEndComments(llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle()) {
+ return fixNamespaceEndComments(
+ Code,
+ /*Ranges=*/{1, tooling::Range(0, Code.size())}, Style);
+ }
+};
+
+TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "}"));
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace\n",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "}\n"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "}"));
+ EXPECT_EQ("inline namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace A",
+ fixNamespaceEndComments("inline namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "}"));
+ EXPECT_EQ("namespace ::A {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace ::A",
+ fixNamespaceEndComments("namespace ::A {\n"
+ " int i;\n"
+ " int j;\n"
+ "}"));
+ EXPECT_EQ("namespace ::A::B {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace ::A::B",
+ fixNamespaceEndComments("namespace ::A::B {\n"
+ " int i;\n"
+ " int j;\n"
+ "}"));
+ EXPECT_EQ("namespace /**/::/**/A/**/::/**/B/**/ {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace ::A::B",
+ fixNamespaceEndComments("namespace /**/::/**/A/**/::/**/B/**/ {\n"
+ " int i;\n"
+ " int j;\n"
+ "}"));
+ EXPECT_EQ("namespace A {\n"
+ "namespace B {\n"
+ " int i;\n"
+ "}\n"
+ "}// namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ "namespace B {\n"
+ " int i;\n"
+ "}\n"
+ "}"));
+ EXPECT_EQ("namespace A {\n"
+ "namespace B {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace B\n"
+ "}// namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ "namespace B {\n"
+ " int i;\n"
+ " int j;\n"
+ "}\n"
+ "}"));
+ EXPECT_EQ("namespace A {\n"
+ " int a;\n"
+ " int b;\n"
+ "}// namespace A\n"
+ "namespace B {\n"
+ " int b;\n"
+ " int a;\n"
+ "}// namespace B",
+ fixNamespaceEndComments("namespace A {\n"
+ " int a;\n"
+ " int b;\n"
+ "}\n"
+ "namespace B {\n"
+ " int b;\n"
+ " int a;\n"
+ "}"));
+ EXPECT_EQ("namespace A {\n"
+ " int a1;\n"
+ " int a2;\n"
+ "}// namespace A\n"
+ "namespace A {\n"
+ " int a2;\n"
+ " int a1;\n"
+ "}// namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int a1;\n"
+ " int a2;\n"
+ "}\n"
+ "namespace A {\n"
+ " int a2;\n"
+ " int a1;\n"
+ "}"));
+ EXPECT_EQ("namespace A {\n"
+ " int a;\n"
+ " int b;\n"
+ "}// namespace A\n"
+ "// comment about b\n"
+ "int b;",
+ fixNamespaceEndComments("namespace A {\n"
+ " int a;\n"
+ " int b;\n"
+ "}\n"
+ "// comment about b\n"
+ "int b;"));
+
+ EXPECT_EQ("namespace A {\n"
+ "namespace B {\n"
+ "namespace C {\n"
+ "namespace D {\n"
+ "}\n"
+ "}// namespace C\n"
+ "}// namespace B\n"
+ "}// namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ "namespace B {\n"
+ "namespace C {\n"
+ "namespace D {\n"
+ "}\n"
+ "}\n"
+ "}\n"
+ "}"));
+
+ // Adds an end comment after a semicolon.
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "};// namespace",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "};"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "};// namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "};"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "};// namespace A\n"
+ "// unrelated",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "};\n"
+ "// unrelated"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest, AddsNewlineIfNeeded) {
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace A\n"
+ " int k;",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "} int k;"));
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace\n"
+ " int k;",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "} int k;"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace A\n"
+ " namespace B {\n"
+ " int j;\n"
+ " int k;\n"
+ "}// namespace B",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ " int j;\n"
+ "} namespace B {\n"
+ " int j;\n"
+ " int k;\n"
+ "}"));
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "};// namespace\n"
+ "int k;",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "};int k;"));
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "};// namespace\n"
+ ";",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "};;"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddEndCommentForShortNamespace) {
+ EXPECT_EQ("namespace {}", fixNamespaceEndComments("namespace {}"));
+ EXPECT_EQ("namespace A {}", fixNamespaceEndComments("namespace A {}"));
+ EXPECT_EQ("namespace A { a }",
+ fixNamespaceEndComments("namespace A { a }"));
+ EXPECT_EQ("namespace A { a };",
+ fixNamespaceEndComments("namespace A { a };"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterUnaffectedRBrace) {
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "}",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "}",
+ // The range (16, 3) spans the 'int' above.
+ /*Ranges=*/{1, tooling::Range(16, 3)}));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "};",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "};",
+ // The range (16, 3) spans the 'int' above.
+ /*Ranges=*/{1, tooling::Range(16, 3)}));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterRBraceInPPDirective) {
+ EXPECT_EQ("#define SAD \\\n"
+ "namespace A { \\\n"
+ " int i; \\\n"
+ "}",
+ fixNamespaceEndComments("#define SAD \\\n"
+ "namespace A { \\\n"
+ " int i; \\\n"
+ "}"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest, KeepsValidEndComment) {
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ "} // end anonymous namespace",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ "} // end anonymous namespace"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} /* end of namespace A */",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} /* end of namespace A */"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} // namespace A"));
+ EXPECT_EQ("namespace A::B {\n"
+ " int i;\n"
+ "} // end namespace A::B",
+ fixNamespaceEndComments("namespace A::B {\n"
+ " int i;\n"
+ "} // end namespace A::B"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "}; // end namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "}; // end namespace A"));
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ "}; /* unnamed namespace */",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ "}; /* unnamed namespace */"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) {
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ "} // namespace",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ "} // namespace A"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} // namespace"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} //"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} //"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} // banamespace A"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "}; // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "}; // banamespace A"));
+ // Updates invalid line comments even for short namespaces.
+ EXPECT_EQ("namespace A {} // namespace A",
+ fixNamespaceEndComments("namespace A {} // namespace"));
+ EXPECT_EQ("namespace A {}; // namespace A",
+ fixNamespaceEndComments("namespace A {}; // namespace"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) {
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ "} // namespace",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ "} /* namespace A */"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} /* end namespace */"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} /**/"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} /* end unnamed namespace */"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "} /* banamespace A */"));
+ EXPECT_EQ("namespace A {\n"
+ " int i;\n"
+ "}; // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ " int i;\n"
+ "}; /* banamespace A */"));
+ EXPECT_EQ("namespace A {} // namespace A",
+ fixNamespaceEndComments("namespace A {} /**/"));
+ EXPECT_EQ("namespace A {}; // namespace A",
+ fixNamespaceEndComments("namespace A {}; /**/"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest,
+ DoesNotAddEndCommentForNamespacesControlledByMacros) {
+ EXPECT_EQ("#ifdef 1\n"
+ "namespace A {\n"
+ "#elseif\n"
+ "namespace B {\n"
+ "#endif\n"
+ " int i;\n"
+ "}\n"
+ "}\n",
+ fixNamespaceEndComments("#ifdef 1\n"
+ "namespace A {\n"
+ "#elseif\n"
+ "namespace B {\n"
+ "#endif\n"
+ " int i;\n"
+ "}\n"
+ "}\n"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest,
+ DoesNotAddEndCommentForNamespacesInMacroDeclarations) {
+ EXPECT_EQ("#ifdef 1\n"
+ "namespace A {\n"
+ "#elseif\n"
+ "namespace B {\n"
+ "#endif\n"
+ " int i;\n"
+ "}\n"
+ "}\n",
+ fixNamespaceEndComments("#ifdef 1\n"
+ "namespace A {\n"
+ "#elseif\n"
+ "namespace B {\n"
+ "#endif\n"
+ " int i;\n"
+ "}\n"
+ "}\n"));
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "}// namespace\n"
+ "#if A\n"
+ " int i;\n"
+ "#else\n"
+ " int j;\n"
+ "#endif",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ " int j;\n"
+ "}\n"
+ "#if A\n"
+ " int i;\n"
+ "#else\n"
+ " int j;\n"
+ "#endif"));
+ EXPECT_EQ("#if A\n"
+ "namespace A {\n"
+ "#else\n"
+ "namespace B {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ fixNamespaceEndComments("#if A\n"
+ "namespace A {\n"
+ "#else\n"
+ "namespace B {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("#if A\n"
+ "namespace A {\n"
+ "#else\n"
+ "namespace B {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("#if A\n"
+ "namespace A {\n"
+ "#else\n"
+ "namespace B {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "} // namespace A"));
+ EXPECT_EQ("#if A\n"
+ "namespace A {\n"
+ "#else\n"
+ "namespace B {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "} // namespace B",
+ fixNamespaceEndComments("#if A\n"
+ "namespace A {\n"
+ "#else\n"
+ "namespace B {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "} // namespace B"));
+ EXPECT_EQ("namespace A\n"
+ "int i;\n"
+ "int j;\n"
+ "#if A\n"
+ "}\n"
+ "#else\n"
+ "}\n"
+ "#endif",
+ fixNamespaceEndComments("namespace A\n"
+ "int i;\n"
+ "int j;\n"
+ "#if A\n"
+ "}\n"
+ "#else\n"
+ "}\n"
+ "#endif"));
+ EXPECT_EQ("namespace A\n"
+ "int i;\n"
+ "int j;\n"
+ "#if A\n"
+ "} // namespace A\n"
+ "#else\n"
+ "} // namespace A\n"
+ "#endif",
+ fixNamespaceEndComments("namespace A\n"
+ "int i;\n"
+ "int j;\n"
+ "#if A\n"
+ "} // namespace A\n"
+ "#else\n"
+ "} // namespace A\n"
+ "#endif"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest,
+ DoesNotAddEndCommentForUnbalancedRBracesAfterNamespaceEnd) {
+ EXPECT_EQ("namespace {\n"
+ " int i;\n"
+ "} // namespace\n"
+ "}",
+ fixNamespaceEndComments("namespace {\n"
+ " int i;\n"
+ "} // namespace\n"
+ "}"));
+}
+
+TEST_F(NamespaceEndCommentsFixerTest, HandlesInlineAtEndOfLine_PR32438) {
+ EXPECT_EQ("template <int> struct a {};\n"
+ "struct a<bool{}> b() {\n"
+ "}\n"
+ "#define c inline\n"
+ "void d() {\n"
+ "}\n",
+ fixNamespaceEndComments("template <int> struct a {};\n"
+ "struct a<bool{}> b() {\n"
+ "}\n"
+ "#define c inline\n"
+ "void d() {\n"
+ "}\n"));
+}
+} // end namespace
+} // end namespace format
+} // end namespace clang
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index 918167bf43c5..b5a6fd90d08f 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -12,6 +12,7 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -64,10 +65,12 @@ protected:
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
VoidModuleLoader ModLoader;
+ MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, HeaderInfo, ModLoader, /*IILookup =*/nullptr,
+ SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ /*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
PP.EnterMainSourceFile();
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index 064abafc4a88..0841791e0863 100644
--- a/unittests/Lex/PPCallbacksTest.cpp
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -14,6 +14,7 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -161,13 +162,14 @@ protected:
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
VoidModuleLoader ModLoader;
+ MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, HeaderInfo, ModLoader,
+ SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
@@ -198,11 +200,12 @@ protected:
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
VoidModuleLoader ModLoader;
+ MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, OpenCLLangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
- OpenCLLangOpts, SourceMgr, HeaderInfo, ModLoader,
+ OpenCLLangOpts, SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
diff --git a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index dccfffdb2c15..b635604e0982 100644
--- a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -12,6 +12,7 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -93,10 +94,11 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
VoidModuleLoader ModLoader;
+ MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, HeaderInfo, ModLoader,
+ SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index 185f43b6a8c5..b5af99bdfd6d 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -13,7 +13,7 @@ endif()
add_clang_unittest(ToolingTests
CommentHandlerTest.cpp
CompilationDatabaseTest.cpp
- FixItTest.cpp
+ FixItTest.cpp
LookupTest.cpp
QualTypeNamesTest.cpp
RecursiveASTVisitorTest.cpp
@@ -38,4 +38,5 @@ target_link_libraries(ToolingTests
clangRewrite
clangTooling
clangToolingCore
+ clangToolingRefactor
)
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index c29f8d7d7123..495ac755b39d 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -26,6 +26,7 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"
@@ -102,10 +103,10 @@ TEST_F(ReplacementTest, ReturnsInvalidPath) {
// Checks that an llvm::Error instance contains a ReplacementError with expected
// error code, expected new replacement, and expected existing replacement.
-static bool checkReplacementError(
- llvm::Error&& Error, replacement_error ExpectedErr,
- llvm::Optional<Replacement> ExpectedExisting,
- llvm::Optional<Replacement> ExpectedNew) {
+static bool checkReplacementError(llvm::Error &&Error,
+ replacement_error ExpectedErr,
+ llvm::Optional<Replacement> ExpectedExisting,
+ llvm::Optional<Replacement> ExpectedNew) {
if (!Error) {
llvm::errs() << "Error is a success.";
return false;
@@ -1089,5 +1090,206 @@ TEST(DeduplicateByFileTest, NonExistingFilePath) {
EXPECT_TRUE(FileToReplaces.empty());
}
+class AtomicChangeTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ DefaultFileID = Context.createInMemoryFile("input.cpp", DefaultCode);
+ DefaultLoc = Context.Sources.getLocForStartOfFile(DefaultFileID)
+ .getLocWithOffset(20);
+ assert(DefaultLoc.isValid() && "Default location must be valid.");
+ }
+
+ RewriterTestContext Context;
+ std::string DefaultCode = std::string(100, 'a');
+ unsigned DefaultOffset = 20;
+ SourceLocation DefaultLoc;
+ FileID DefaultFileID;
+};
+
+TEST_F(AtomicChangeTest, AtomicChangeToYAML) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ llvm::Error Err =
+ Change.insert(Context.Sources, DefaultLoc, "aa", /*InsertAfter=*/false);
+ ASSERT_TRUE(!Err);
+ Err = Change.insert(Context.Sources, DefaultLoc.getLocWithOffset(10), "bb",
+ /*InsertAfter=*/false);
+ ASSERT_TRUE(!Err);
+ Change.addHeader("a.h");
+ Change.removeHeader("b.h");
+ std::string YAMLString = Change.toYAMLString();
+
+ // NOTE: If this test starts to fail for no obvious reason, check whitespace.
+ ASSERT_STREQ("---\n"
+ "Key: 'input.cpp:20'\n"
+ "FilePath: input.cpp\n"
+ "Error: ''\n"
+ "InsertedHeaders: [ a.h ]\n"
+ "RemovedHeaders: [ b.h ]\n"
+ "Replacements: \n" // Extra whitespace here!
+ " - FilePath: input.cpp\n"
+ " Offset: 20\n"
+ " Length: 0\n"
+ " ReplacementText: aa\n"
+ " - FilePath: input.cpp\n"
+ " Offset: 30\n"
+ " Length: 0\n"
+ " ReplacementText: bb\n"
+ "...\n",
+ YAMLString.c_str());
+}
+
+TEST_F(AtomicChangeTest, YAMLToAtomicChange) {
+ std::string YamlContent = "---\n"
+ "Key: 'input.cpp:20'\n"
+ "FilePath: input.cpp\n"
+ "Error: 'ok'\n"
+ "InsertedHeaders: [ a.h ]\n"
+ "RemovedHeaders: [ b.h ]\n"
+ "Replacements: \n" // Extra whitespace here!
+ " - FilePath: input.cpp\n"
+ " Offset: 20\n"
+ " Length: 0\n"
+ " ReplacementText: aa\n"
+ " - FilePath: input.cpp\n"
+ " Offset: 30\n"
+ " Length: 0\n"
+ " ReplacementText: bb\n"
+ "...\n";
+ AtomicChange ExpectedChange(Context.Sources, DefaultLoc);
+ llvm::Error Err = ExpectedChange.insert(Context.Sources, DefaultLoc, "aa",
+ /*InsertAfter=*/false);
+ ASSERT_TRUE(!Err);
+ Err = ExpectedChange.insert(Context.Sources, DefaultLoc.getLocWithOffset(10),
+ "bb", /*InsertAfter=*/false);
+ ASSERT_TRUE(!Err);
+
+ ExpectedChange.addHeader("a.h");
+ ExpectedChange.removeHeader("b.h");
+ ExpectedChange.setError("ok");
+
+ AtomicChange ActualChange = AtomicChange::convertFromYAML(YamlContent);
+ EXPECT_EQ(ExpectedChange.getKey(), ActualChange.getKey());
+ EXPECT_EQ(ExpectedChange.getFilePath(), ActualChange.getFilePath());
+ EXPECT_EQ(ExpectedChange.getError(), ActualChange.getError());
+ EXPECT_EQ(ExpectedChange.getInsertedHeaders(),
+ ActualChange.getInsertedHeaders());
+ EXPECT_EQ(ExpectedChange.getRemovedHeaders(),
+ ActualChange.getRemovedHeaders());
+ EXPECT_EQ(ExpectedChange.getReplacements().size(),
+ ActualChange.getReplacements().size());
+ EXPECT_EQ(2u, ActualChange.getReplacements().size());
+ EXPECT_EQ(*ExpectedChange.getReplacements().begin(),
+ *ActualChange.getReplacements().begin());
+ EXPECT_EQ(*(++ExpectedChange.getReplacements().begin()),
+ *(++ActualChange.getReplacements().begin()));
+}
+
+TEST_F(AtomicChangeTest, CheckKeyAndKeyFile) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ EXPECT_EQ("input.cpp:20", Change.getKey());
+ EXPECT_EQ("input.cpp", Change.getFilePath());
+}
+
+TEST_F(AtomicChangeTest, Replace) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ llvm::Error Err = Change.replace(Context.Sources, DefaultLoc, 2, "aa");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ(Change.getReplacements().size(), 1u);
+ EXPECT_EQ(*Change.getReplacements().begin(),
+ Replacement(Context.Sources, DefaultLoc, 2, "aa"));
+
+ // Add a new replacement that conflicts with the existing one.
+ Err = Change.replace(Context.Sources, DefaultLoc, 3, "ab");
+ EXPECT_TRUE((bool)Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(Change.getReplacements().size(), 1u);
+}
+
+TEST_F(AtomicChangeTest, ReplaceWithRange) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ SourceLocation End = DefaultLoc.getLocWithOffset(20);
+ llvm::Error Err = Change.replace(
+ Context.Sources, CharSourceRange::getCharRange(DefaultLoc, End), "aa");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ(Change.getReplacements().size(), 1u);
+ EXPECT_EQ(*Change.getReplacements().begin(),
+ Replacement(Context.Sources, DefaultLoc, 20, "aa"));
+}
+
+TEST_F(AtomicChangeTest, InsertBefore) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "aa");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ(Change.getReplacements().size(), 1u);
+ EXPECT_EQ(*Change.getReplacements().begin(),
+ Replacement(Context.Sources, DefaultLoc, 0, "aa"));
+ Err = Change.insert(Context.Sources, DefaultLoc, "b", /*InsertAfter=*/false);
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ(Change.getReplacements().size(), 1u);
+ EXPECT_EQ(*Change.getReplacements().begin(),
+ Replacement(Context.Sources, DefaultLoc, 0, "baa"));
+}
+
+TEST_F(AtomicChangeTest, InsertAfter) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "aa");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ(Change.getReplacements().size(), 1u);
+ EXPECT_EQ(*Change.getReplacements().begin(),
+ Replacement(Context.Sources, DefaultLoc, 0, "aa"));
+ Err = Change.insert(Context.Sources, DefaultLoc, "b");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ(Change.getReplacements().size(), 1u);
+ EXPECT_EQ(*Change.getReplacements().begin(),
+ Replacement(Context.Sources, DefaultLoc, 0, "aab"));
+}
+
+TEST_F(AtomicChangeTest, InsertBeforeWithInvalidLocation) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ llvm::Error Err =
+ Change.insert(Context.Sources, DefaultLoc, "a", /*InsertAfter=*/false);
+ ASSERT_TRUE(!Err);
+
+ // Invalid location.
+ Err = Change.insert(Context.Sources, SourceLocation(), "a",
+ /*InsertAfter=*/false);
+ ASSERT_TRUE((bool)Err);
+ EXPECT_TRUE(checkReplacementError(
+ std::move(Err), replacement_error::wrong_file_path,
+ Replacement(Context.Sources, DefaultLoc, 0, "a"),
+ Replacement(Context.Sources, SourceLocation(), 0, "a")));
+}
+
+TEST_F(AtomicChangeTest, InsertBeforeToWrongFile) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ llvm::Error Err =
+ Change.insert(Context.Sources, DefaultLoc, "a", /*InsertAfter=*/false);
+ ASSERT_TRUE(!Err);
+
+ // Inserting at a different file.
+ FileID NewID = Context.createInMemoryFile("extra.cpp", DefaultCode);
+ SourceLocation NewLoc = Context.Sources.getLocForStartOfFile(NewID);
+ Err = Change.insert(Context.Sources, NewLoc, "b", /*InsertAfter=*/false);
+ ASSERT_TRUE((bool)Err);
+ EXPECT_TRUE(
+ checkReplacementError(std::move(Err), replacement_error::wrong_file_path,
+ Replacement(Context.Sources, DefaultLoc, 0, "a"),
+ Replacement(Context.Sources, NewLoc, 0, "b")));
+}
+
+TEST_F(AtomicChangeTest, InsertAfterWithInvalidLocation) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "a");
+ ASSERT_TRUE(!Err);
+
+ // Invalid location.
+ Err = Change.insert(Context.Sources, SourceLocation(), "b");
+ ASSERT_TRUE((bool)Err);
+ EXPECT_TRUE(checkReplacementError(
+ std::move(Err), replacement_error::wrong_file_path,
+ Replacement(Context.Sources, DefaultLoc, 0, "a"),
+ Replacement(Context.Sources, SourceLocation(), 0, "b")));
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 29a1eedb7af8..c8e9537cb56b 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -7,6 +7,7 @@ add_tablegen(clang-tblgen CLANG
ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
ClangCommentHTMLTagsEmitter.cpp
ClangDiagnosticsEmitter.cpp
+ ClangOptionDocEmitter.cpp
ClangSACheckersEmitter.cpp
NeonEmitter.cpp
TableGen.cpp
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 27ab34c1309d..8aaa28beaac2 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -90,13 +90,13 @@ GetFlattenedSpellings(const Record &Attr) {
static std::string ReadPCHRecord(StringRef type) {
return StringSwitch<std::string>(type)
- .EndsWith("Decl *", "GetLocalDeclAs<"
- + std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])")
- .Case("TypeSourceInfo *", "GetTypeSourceInfo(F, Record, Idx)")
- .Case("Expr *", "ReadExpr(F)")
- .Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
- .Case("StringRef", "ReadString(Record, Idx)")
- .Default("Record[Idx++]");
+ .EndsWith("Decl *", "Record.GetLocalDeclAs<"
+ + std::string(type, 0, type.size()-1) + ">(Record.readInt())")
+ .Case("TypeSourceInfo *", "Record.getTypeSourceInfo()")
+ .Case("Expr *", "Record.readExpr()")
+ .Case("IdentifierInfo *", "Record.getIdentifierInfo()")
+ .Case("StringRef", "Record.readString()")
+ .Default("Record.readInt()");
}
// Get a type that is suitable for storing an object of the specified type.
@@ -413,7 +413,7 @@ namespace {
void writePCHReadDecls(raw_ostream &OS) const override {
OS << " std::string " << getLowerName()
- << "= ReadString(Record, Idx);\n";
+ << "= Record.readString();\n";
}
void writePCHReadArgs(raw_ostream &OS) const override {
@@ -539,13 +539,13 @@ namespace {
}
void writePCHReadDecls(raw_ostream &OS) const override {
- OS << " bool is" << getLowerName() << "Expr = Record[Idx++];\n";
+ OS << " bool is" << getLowerName() << "Expr = Record.readInt();\n";
OS << " void *" << getLowerName() << "Ptr;\n";
OS << " if (is" << getLowerName() << "Expr)\n";
- OS << " " << getLowerName() << "Ptr = ReadExpr(F);\n";
+ OS << " " << getLowerName() << "Ptr = Record.readExpr();\n";
OS << " else\n";
OS << " " << getLowerName()
- << "Ptr = GetTypeSourceInfo(F, Record, Idx);\n";
+ << "Ptr = Record.getTypeSourceInfo();\n";
}
void writePCHWrite(raw_ostream &OS) const override {
@@ -658,7 +658,7 @@ namespace {
}
void writePCHReadDecls(raw_ostream &OS) const override {
- OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n";
+ OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n";
OS << " SmallVector<" << getType() << ", 4> "
<< getLowerName() << ";\n";
OS << " " << getLowerName() << ".reserve(" << getLowerName()
@@ -783,7 +783,7 @@ namespace {
void writePCHReadDecls(raw_ostream &OS) const override {
OS << " " << getAttrName() << "Attr::" << type << " " << getLowerName()
<< "(static_cast<" << getAttrName() << "Attr::" << type
- << ">(Record[Idx++]));\n";
+ << ">(Record.readInt()));\n";
}
void writePCHReadArgs(raw_ostream &OS) const override {
@@ -906,14 +906,14 @@ namespace {
}
void writePCHReadDecls(raw_ostream &OS) const override {
- OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n";
+ OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n";
OS << " SmallVector<" << QualifiedTypeName << ", 4> " << getLowerName()
<< ";\n";
OS << " " << getLowerName() << ".reserve(" << getLowerName()
<< "Size);\n";
OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
OS << " " << getLowerName() << ".push_back(" << "static_cast<"
- << QualifiedTypeName << ">(Record[Idx++]));\n";
+ << QualifiedTypeName << ">(Record.readInt()));\n";
}
void writePCHWrite(raw_ostream &OS) const override {
@@ -996,7 +996,7 @@ namespace {
void writePCHReadDecls(raw_ostream &OS) const override {
OS << " VersionTuple " << getLowerName()
- << "= ReadVersionTuple(Record, Idx);\n";
+ << "= Record.readVersionTuple();\n";
}
void writePCHReadArgs(raw_ostream &OS) const override {
@@ -1036,7 +1036,7 @@ namespace {
OS << " " << getType() << " tempInst" << getUpperName() << ";\n";
OS << " {\n";
OS << " EnterExpressionEvaluationContext "
- << "Unevaluated(S, Sema::Unevaluated);\n";
+ << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
OS << " ExprResult " << "Result = S.SubstExpr("
<< "A->get" << getUpperName() << "(), TemplateArgs);\n";
OS << " tempInst" << getUpperName() << " = "
@@ -1083,7 +1083,7 @@ namespace {
<< "[A->" << getLowerName() << "_size()];\n";
OS << " {\n";
OS << " EnterExpressionEvaluationContext "
- << "Unevaluated(S, Sema::Unevaluated);\n";
+ << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
OS << " " << getType() << " *TI = tempInst" << getUpperName()
<< ";\n";
OS << " " << getType() << " *I = A->" << getLowerName()
@@ -2126,9 +2126,9 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
OS << " case attr::" << R.getName() << ": {\n";
if (R.isSubClassOf(InhClass))
- OS << " bool isInherited = Record[Idx++];\n";
- OS << " bool isImplicit = Record[Idx++];\n";
- OS << " unsigned Spelling = Record[Idx++];\n";
+ OS << " bool isInherited = Record.readInt();\n";
+ OS << " bool isImplicit = Record.readInt();\n";
+ OS << " unsigned Spelling = Record.readInt();\n";
ArgRecords = R.getValueAsListOfDefs("Args");
Args.clear();
for (const auto *Arg : ArgRecords) {
@@ -2451,26 +2451,19 @@ void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) {
OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n";
}
-// Emits code to instantiate dependent attributes on templates.
-void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Template instantiation code for attributes", OS);
-
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
-
- OS << "namespace clang {\n"
- << "namespace sema {\n\n"
- << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
- << "Sema &S,\n"
- << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"
- << " switch (At->getKind()) {\n";
+void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
+ raw_ostream &OS,
+ bool AppliesToDecl) {
+ OS << " switch (At->getKind()) {\n";
for (const auto *Attr : Attrs) {
const Record &R = *Attr;
if (!R.getValueAsBit("ASTNode"))
continue;
-
OS << " case attr::" << R.getName() << ": {\n";
- bool ShouldClone = R.getValueAsBit("Clone");
+ bool ShouldClone = R.getValueAsBit("Clone") &&
+ (!AppliesToDecl ||
+ R.getValueAsBit("MeaningfulToClassTemplateDefinition"));
if (!ShouldClone) {
OS << " return nullptr;\n";
@@ -2507,8 +2500,27 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
}
OS << " } // end switch\n"
<< " llvm_unreachable(\"Unknown attribute!\");\n"
- << " return nullptr;\n"
- << "}\n\n"
+ << " return nullptr;\n";
+}
+
+// Emits code to instantiate dependent attributes on templates.
+void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Template instantiation code for attributes", OS);
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ OS << "namespace clang {\n"
+ << "namespace sema {\n\n"
+ << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
+ << "Sema &S,\n"
+ << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
+ EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/false);
+ OS << "}\n\n"
+ << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n"
+ << " ASTContext &C, Sema &S,\n"
+ << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
+ EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true);
+ OS << "}\n\n"
<< "} // end namespace sema\n"
<< "} // end namespace clang\n";
}
diff --git a/utils/TableGen/ClangOptionDocEmitter.cpp b/utils/TableGen/ClangOptionDocEmitter.cpp
new file mode 100644
index 000000000000..aa7502e2c850
--- /dev/null
+++ b/utils/TableGen/ClangOptionDocEmitter.cpp
@@ -0,0 +1,391 @@
+//===- ClangOptionDocEmitter.cpp - Documentation for command line flags ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// FIXME: Once this has stabilized, consider moving it to LLVM.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TableGen/Error.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cctype>
+#include <cstring>
+#include <map>
+
+using namespace llvm;
+
+namespace clang {
+namespace docs {
+namespace {
+struct DocumentedOption {
+ Record *Option;
+ std::vector<Record*> Aliases;
+};
+struct DocumentedGroup;
+struct Documentation {
+ std::vector<DocumentedGroup> Groups;
+ std::vector<DocumentedOption> Options;
+};
+struct DocumentedGroup : Documentation {
+ Record *Group;
+};
+
+// Reorganize the records into a suitable form for emitting documentation.
+Documentation extractDocumentation(RecordKeeper &Records) {
+ Documentation Result;
+
+ // Build the tree of groups. The root in the tree is the fake option group
+ // (Record*)nullptr, which contains all top-level groups and options.
+ std::map<Record*, std::vector<Record*> > OptionsInGroup;
+ std::map<Record*, std::vector<Record*> > GroupsInGroup;
+ std::map<Record*, std::vector<Record*> > Aliases;
+
+ std::map<std::string, Record*> OptionsByName;
+ for (Record *R : Records.getAllDerivedDefinitions("Option"))
+ OptionsByName[R->getValueAsString("Name")] = R;
+
+ auto Flatten = [](Record *R) {
+ return R->getValue("DocFlatten") && R->getValueAsBit("DocFlatten");
+ };
+
+ auto SkipFlattened = [&](Record *R) -> Record* {
+ while (R && Flatten(R)) {
+ auto *G = dyn_cast<DefInit>(R->getValueInit("Group"));
+ if (!G)
+ return nullptr;
+ R = G->getDef();
+ }
+ return R;
+ };
+
+ for (Record *R : Records.getAllDerivedDefinitions("OptionGroup")) {
+ if (Flatten(R))
+ continue;
+
+ Record *Group = nullptr;
+ if (auto *G = dyn_cast<DefInit>(R->getValueInit("Group")))
+ Group = SkipFlattened(G->getDef());
+ GroupsInGroup[Group].push_back(R);
+ }
+
+ for (Record *R : Records.getAllDerivedDefinitions("Option")) {
+ if (auto *A = dyn_cast<DefInit>(R->getValueInit("Alias"))) {
+ Aliases[A->getDef()].push_back(R);
+ continue;
+ }
+
+ // Pretend no-X and Xno-Y options are aliases of X and XY.
+ auto Name = R->getValueAsString("Name");
+ if (Name.size() >= 4) {
+ if (Name.substr(0, 3) == "no-" && OptionsByName[Name.substr(3)]) {
+ Aliases[OptionsByName[Name.substr(3)]].push_back(R);
+ continue;
+ }
+ if (Name.substr(1, 3) == "no-" && OptionsByName[Name[0] + Name.substr(4)]) {
+ Aliases[OptionsByName[Name[0] + Name.substr(4)]].push_back(R);
+ continue;
+ }
+ }
+
+ Record *Group = nullptr;
+ if (auto *G = dyn_cast<DefInit>(R->getValueInit("Group")))
+ Group = SkipFlattened(G->getDef());
+ OptionsInGroup[Group].push_back(R);
+ }
+
+ auto CompareByName = [](Record *A, Record *B) {
+ return A->getValueAsString("Name") < B->getValueAsString("Name");
+ };
+
+ auto CompareByLocation = [](Record *A, Record *B) {
+ return A->getLoc()[0].getPointer() < B->getLoc()[0].getPointer();
+ };
+
+ auto DocumentationForOption = [&](Record *R) -> DocumentedOption {
+ auto &A = Aliases[R];
+ std::sort(A.begin(), A.end(), CompareByName);
+ return {R, std::move(A)};
+ };
+
+ std::function<Documentation(Record *)> DocumentationForGroup =
+ [&](Record *R) -> Documentation {
+ Documentation D;
+
+ auto &Groups = GroupsInGroup[R];
+ std::sort(Groups.begin(), Groups.end(), CompareByLocation);
+ for (Record *G : Groups) {
+ D.Groups.emplace_back();
+ D.Groups.back().Group = G;
+ Documentation &Base = D.Groups.back();
+ Base = DocumentationForGroup(G);
+ }
+
+ auto &Options = OptionsInGroup[R];
+ std::sort(Options.begin(), Options.end(), CompareByName);
+ for (Record *O : Options)
+ D.Options.push_back(DocumentationForOption(O));
+
+ return D;
+ };
+
+ return DocumentationForGroup(nullptr);
+}
+
+// Get the first and successive separators to use for an OptionKind.
+std::pair<StringRef,StringRef> getSeparatorsForKind(const Record *OptionKind) {
+ return StringSwitch<std::pair<StringRef, StringRef>>(OptionKind->getName())
+ .Cases("KIND_JOINED", "KIND_JOINED_OR_SEPARATE",
+ "KIND_JOINED_AND_SEPARATE",
+ "KIND_REMAINING_ARGS_JOINED", {"", " "})
+ .Case("KIND_COMMAJOINED", {"", ","})
+ .Default({" ", " "});
+}
+
+const unsigned UnlimitedArgs = unsigned(-1);
+
+// Get the number of arguments expected for an option, or -1 if any number of
+// arguments are accepted.
+unsigned getNumArgsForKind(Record *OptionKind, const Record *Option) {
+ return StringSwitch<unsigned>(OptionKind->getName())
+ .Cases("KIND_JOINED", "KIND_JOINED_OR_SEPARATE", "KIND_SEPARATE", 1)
+ .Cases("KIND_REMAINING_ARGS", "KIND_REMAINING_ARGS_JOINED",
+ "KIND_COMMAJOINED", UnlimitedArgs)
+ .Case("KIND_JOINED_AND_SEPARATE", 2)
+ .Case("KIND_MULTIARG", Option->getValueAsInt("NumArgs"))
+ .Default(0);
+}
+
+bool hasFlag(const Record *OptionOrGroup, StringRef OptionFlag) {
+ for (const Record *Flag : OptionOrGroup->getValueAsListOfDefs("Flags"))
+ if (Flag->getName() == OptionFlag)
+ return true;
+ return false;
+}
+
+bool isExcluded(const Record *OptionOrGroup, const Record *DocInfo) {
+ // FIXME: Provide a flag to specify the set of exclusions.
+ for (StringRef Exclusion : DocInfo->getValueAsListOfStrings("ExcludedFlags"))
+ if (hasFlag(OptionOrGroup, Exclusion))
+ return true;
+ return false;
+}
+
+std::string escapeRST(StringRef Str) {
+ std::string Out;
+ for (auto K : Str) {
+ if (StringRef("`*|_[]\\").count(K))
+ Out.push_back('\\');
+ Out.push_back(K);
+ }
+ return Out;
+}
+
+StringRef getSphinxOptionID(StringRef OptionName) {
+ for (auto I = OptionName.begin(), E = OptionName.end(); I != E; ++I)
+ if (!isalnum(*I) && *I != '-')
+ return OptionName.substr(0, I - OptionName.begin());
+ return OptionName;
+}
+
+bool canSphinxCopeWithOption(const Record *Option) {
+ // HACK: Work arond sphinx's inability to cope with punctuation-only options
+ // such as /? by suppressing them from the option list.
+ for (char C : Option->getValueAsString("Name"))
+ if (isalnum(C))
+ return true;
+ return false;
+}
+
+void emitHeading(int Depth, std::string Heading, raw_ostream &OS) {
+ assert(Depth < 8 && "groups nested too deeply");
+ OS << Heading << '\n'
+ << std::string(Heading.size(), "=~-_'+<>"[Depth]) << "\n";
+}
+
+/// Get the value of field \p Primary, if possible. If \p Primary does not
+/// exist, get the value of \p Fallback and escape it for rST emission.
+std::string getRSTStringWithTextFallback(const Record *R, StringRef Primary,
+ StringRef Fallback) {
+ for (auto Field : {Primary, Fallback}) {
+ if (auto *V = R->getValue(Field)) {
+ StringRef Value;
+ if (auto *SV = dyn_cast_or_null<StringInit>(V->getValue()))
+ Value = SV->getValue();
+ else if (auto *CV = dyn_cast_or_null<CodeInit>(V->getValue()))
+ Value = CV->getValue();
+ if (!Value.empty())
+ return Field == Primary ? Value.str() : escapeRST(Value);
+ }
+ }
+ return StringRef();
+}
+
+void emitOptionWithArgs(StringRef Prefix, const Record *Option,
+ ArrayRef<std::string> Args, raw_ostream &OS) {
+ OS << Prefix << escapeRST(Option->getValueAsString("Name"));
+
+ std::pair<StringRef, StringRef> Separators =
+ getSeparatorsForKind(Option->getValueAsDef("Kind"));
+
+ StringRef Separator = Separators.first;
+ for (auto Arg : Args) {
+ OS << Separator << escapeRST(Arg);
+ Separator = Separators.second;
+ }
+}
+
+void emitOptionName(StringRef Prefix, const Record *Option, raw_ostream &OS) {
+ // Find the arguments to list after the option.
+ unsigned NumArgs = getNumArgsForKind(Option->getValueAsDef("Kind"), Option);
+
+ std::vector<std::string> Args;
+ if (!Option->isValueUnset("MetaVarName"))
+ Args.push_back(Option->getValueAsString("MetaVarName"));
+ else if (NumArgs == 1)
+ Args.push_back("<arg>");
+
+ while (Args.size() < NumArgs) {
+ Args.push_back(("<arg" + Twine(Args.size() + 1) + ">").str());
+ // Use '--args <arg1> <arg2>...' if any number of args are allowed.
+ if (Args.size() == 2 && NumArgs == UnlimitedArgs) {
+ Args.back() += "...";
+ break;
+ }
+ }
+
+ emitOptionWithArgs(Prefix, Option, Args, OS);
+
+ auto AliasArgs = Option->getValueAsListOfStrings("AliasArgs");
+ if (!AliasArgs.empty()) {
+ Record *Alias = Option->getValueAsDef("Alias");
+ OS << " (equivalent to ";
+ emitOptionWithArgs(Alias->getValueAsListOfStrings("Prefixes").front(),
+ Alias, Option->getValueAsListOfStrings("AliasArgs"), OS);
+ OS << ")";
+ }
+}
+
+bool emitOptionNames(const Record *Option, raw_ostream &OS, bool EmittedAny) {
+ for (auto &Prefix : Option->getValueAsListOfStrings("Prefixes")) {
+ if (EmittedAny)
+ OS << ", ";
+ emitOptionName(Prefix, Option, OS);
+ EmittedAny = true;
+ }
+ return EmittedAny;
+}
+
+template <typename Fn>
+void forEachOptionName(const DocumentedOption &Option, const Record *DocInfo,
+ Fn F) {
+ F(Option.Option);
+
+ for (auto *Alias : Option.Aliases)
+ if (!isExcluded(Alias, DocInfo) && canSphinxCopeWithOption(Option.Option))
+ F(Alias);
+}
+
+void emitOption(const DocumentedOption &Option, const Record *DocInfo,
+ raw_ostream &OS) {
+ if (isExcluded(Option.Option, DocInfo))
+ return;
+ if (Option.Option->getValueAsDef("Kind")->getName() == "KIND_UNKNOWN" ||
+ Option.Option->getValueAsDef("Kind")->getName() == "KIND_INPUT")
+ return;
+ if (!canSphinxCopeWithOption(Option.Option))
+ return;
+
+ // HACK: Emit a different program name with each option to work around
+ // sphinx's inability to cope with options that differ only by punctuation
+ // (eg -ObjC vs -ObjC++, -G vs -G=).
+ std::vector<std::string> SphinxOptionIDs;
+ forEachOptionName(Option, DocInfo, [&](const Record *Option) {
+ for (auto &Prefix : Option->getValueAsListOfStrings("Prefixes"))
+ SphinxOptionIDs.push_back(
+ getSphinxOptionID(Prefix + Option->getValueAsString("Name")));
+ });
+ assert(!SphinxOptionIDs.empty() && "no flags for option");
+ static std::map<std::string, int> NextSuffix;
+ int SphinxWorkaroundSuffix = NextSuffix[*std::max_element(
+ SphinxOptionIDs.begin(), SphinxOptionIDs.end(),
+ [&](const std::string &A, const std::string &B) {
+ return NextSuffix[A] < NextSuffix[B];
+ })];
+ for (auto &S : SphinxOptionIDs)
+ NextSuffix[S] = SphinxWorkaroundSuffix + 1;
+ if (SphinxWorkaroundSuffix)
+ OS << ".. program:: " << DocInfo->getValueAsString("Program")
+ << SphinxWorkaroundSuffix << "\n";
+
+ // Emit the names of the option.
+ OS << ".. option:: ";
+ bool EmittedAny = false;
+ forEachOptionName(Option, DocInfo, [&](const Record *Option) {
+ EmittedAny = emitOptionNames(Option, OS, EmittedAny);
+ });
+ if (SphinxWorkaroundSuffix)
+ OS << "\n.. program:: " << DocInfo->getValueAsString("Program");
+ OS << "\n\n";
+
+ // Emit the description, if we have one.
+ std::string Description =
+ getRSTStringWithTextFallback(Option.Option, "DocBrief", "HelpText");
+ if (!Description.empty())
+ OS << Description << "\n\n";
+}
+
+void emitDocumentation(int Depth, const Documentation &Doc,
+ const Record *DocInfo, raw_ostream &OS);
+
+void emitGroup(int Depth, const DocumentedGroup &Group, const Record *DocInfo,
+ raw_ostream &OS) {
+ if (isExcluded(Group.Group, DocInfo))
+ return;
+
+ emitHeading(Depth,
+ getRSTStringWithTextFallback(Group.Group, "DocName", "Name"), OS);
+
+ // Emit the description, if we have one.
+ std::string Description =
+ getRSTStringWithTextFallback(Group.Group, "DocBrief", "HelpText");
+ if (!Description.empty())
+ OS << Description << "\n\n";
+
+ // Emit contained options and groups.
+ emitDocumentation(Depth + 1, Group, DocInfo, OS);
+}
+
+void emitDocumentation(int Depth, const Documentation &Doc,
+ const Record *DocInfo, raw_ostream &OS) {
+ for (auto &O : Doc.Options)
+ emitOption(O, DocInfo, OS);
+ for (auto &G : Doc.Groups)
+ emitGroup(Depth, G, DocInfo, OS);
+}
+
+} // namespace
+} // namespace docs
+
+void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) {
+ using namespace docs;
+
+ const Record *DocInfo = Records.getDef("GlobalDocumentation");
+ if (!DocInfo) {
+ PrintFatalError("The GlobalDocumentation top-level definition is missing, "
+ "no documentation will be generated.");
+ return;
+ }
+ OS << DocInfo->getValueAsString("Intro") << "\n";
+ OS << ".. program:: " << DocInfo->getValueAsString("Program") << "\n";
+
+ emitDocumentation(0, extractDocumentation(Records), DocInfo, OS);
+}
+} // end namespace clang
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 6fb5b00c4bac..fd7999be3877 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -53,7 +53,8 @@ enum ActionType {
GenArmNeonSema,
GenArmNeonTest,
GenAttrDocs,
- GenDiagDocs
+ GenDiagDocs,
+ GenOptDocs
};
namespace {
@@ -135,7 +136,9 @@ cl::opt<ActionType> Action(
clEnumValN(GenAttrDocs, "gen-attr-docs",
"Generate attribute documentation"),
clEnumValN(GenDiagDocs, "gen-diag-docs",
- "Generate attribute documentation")));
+ "Generate diagnostic documentation"),
+ clEnumValN(GenOptDocs, "gen-opt-docs",
+ "Generate option documentation")));
cl::opt<std::string>
ClangComponent("clang-component",
@@ -238,6 +241,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenDiagDocs:
EmitClangDiagDocs(Records, OS);
break;
+ case GenOptDocs:
+ EmitClangOptDocs(Records, OS);
+ break;
}
return false;
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 0305ed1c8c8f..033cb78f36f3 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -70,6 +70,7 @@ void EmitNeonTest2(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS);
void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS);
} // end namespace clang
diff --git a/www/analyzer/alpha_checks.html b/www/analyzer/alpha_checks.html
index 0312d16aced4..ce9392b9960c 100644
--- a/www/analyzer/alpha_checks.html
+++ b/www/analyzer/alpha_checks.html
@@ -910,6 +910,30 @@ void test(char *y) {
}
</pre></div></div></td></tr>
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.cstring.BlockInCriticalSection</span><span class="lang">
+(C)</span><div class="descr">
+Check for calls to blocking functions inside a critical section; applies
+to:<div class=functions>
+lock, unlock<br>
+sleep<br>
+getc<br>
+fgets<br>
+read<br>
+recv<br>
+pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock<br>
+mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock<br>
+</div></div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void testBlockInCriticalSection() {
+ std::mutex m;
+ m.lock();
+ sleep(3); // warn
+ m.unlock();
+}
+</pre></div></div></td></tr>
</tbody></table>
</div> <!-- page -->
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
index 73727c014b4e..a01e0dd8dddb 100644
--- a/www/cxx_dr_status.html
+++ b/www/cxx_dr_status.html
@@ -28,7 +28,7 @@
<!--*************************************************************************-->
<h1>C++ Defect Report Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2017-01-13 17:52:17 +0100 (Fri, 13 Jan 2017) $</p>
+<p>Last updated: $Date: 2017-03-17 22:41:20 +0100 (Fri, 17 Mar 2017) $</p>
<h2 id="cxxdr">C++ defect report implementation status</h2>
@@ -921,7 +921,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#147">147</a></td>
<td>TC1</td>
<td>Naming the constructor</td>
- <td class="none" align="center">No</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="148">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#148">148</a></td>
@@ -1937,7 +1937,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#316">316</a></td>
<td>NAD</td>
<td>Injected-class-name of template used as template template parameter</td>
- <td class="none" align="center">Superseded by <a href="#1004">1004</a></td>
+ <td class="svn" align="center">Superseded by <a href="#1004">1004</a></td>
</tr>
<tr id="317">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#317">317</a></td>
@@ -1949,7 +1949,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#318">318</a></td>
<td>CD1</td>
<td><TT>struct A::A</TT> should not name the constructor of <TT>A</TT></td>
- <td class="none" align="center">Superseded by <a href="#1310">1310</a></td>
+ <td class="svn" align="center">Superseded by <a href="#1310">1310</a></td>
</tr>
<tr id="319">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#319">319</a></td>
@@ -2279,7 +2279,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#373">373</a></td>
<td>C++11</td>
<td>Lookup on namespace qualified name in using-directive</td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr id="374">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#374">374</a></td>
@@ -5839,7 +5839,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1004">1004</a></td>
<td>C++11</td>
<td>Injected-class-names as arguments for template template parameters</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr id="1005">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1005">1005</a></td>
@@ -7405,7 +7405,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1265">1265</a></td>
<td>CD3</td>
<td>Mixed use of the <TT>auto</TT> specifier</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr class="open" id="1266">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1266">1266</a></td>
@@ -7675,7 +7675,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1310">1310</a></td>
<td>CD3</td>
<td>What is an &#8220;acceptable lookup result?&#8221;</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr id="1311">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1311">1311</a></td>
@@ -7897,7 +7897,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1347">1347</a></td>
<td>CD3</td>
<td>Consistency of <TT>auto</TT> in multiple-declarator declarations</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="1348">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1348">1348</a></td>
@@ -9481,7 +9481,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1611">1611</a></td>
<td>C++14</td>
<td>Deleted default constructor for abstract class</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">Duplicate of <a href="#1658">1658</a></td>
</tr>
<tr id="1612">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1612">1612</a></td>
@@ -9763,7 +9763,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1658">1658</a></td>
<td>C++14</td>
<td>Deleted default constructor for abstract class via destructor</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr class="open" id="1659">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1659">1659</a></td>
@@ -12895,7 +12895,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2180">2180</a></td>
<td>DR</td>
<td>Virtual bases in destructors and defaulted assignment operators</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="2181">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2181">2181</a></td>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index e55f45fffe5c..de0c491e52d7 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -25,7 +25,7 @@
<!--*************************************************************************-->
<h1>C++ Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2017-01-13 17:52:17 +0100 (Fri, 13 Jan 2017) $</p>
+<p>Last updated: $Date: 2017-03-16 15:21:00 +0100 (Thu, 16 Mar 2017) $</p>
<p>Clang fully implements all published ISO C++ standards (<a
href="#cxx98">C++98 / C++03</a>, <a
@@ -612,7 +612,7 @@ as the draft C++1z standard evolves.
<tr>
<td>Make exception specifications part of the type system</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html">P0012R1</a></td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr>
<td><tt>__has_include</tt> in preprocessor conditionals</td>
@@ -648,7 +648,7 @@ as the draft C++1z standard evolves.
<tr>
<td><tt>constexpr</tt> lambda expressions</td>
<td><a href="http://wg21.link/p0170r1">P0170R1</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Differing <tt>begin</tt> and <tt>end</tt> types in range-based <tt>for</tt></td>
@@ -679,27 +679,30 @@ as the draft C++1z standard evolves.
<tr>
<td>Dynamic memory allocation for over-aligned data</td>
<td><a href="http://wg21.link/p0035r4">P0035R4</a></td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr>
- <td>Template argument deduction for class templates</td>
+ <td rowspan="2">Template argument deduction for class templates</td>
<td><a href="http://wg21.link/p0091r3">P0091R3</a></td>
- <td class="none" align="center">No</td>
+ <td rowspan="2" class="svn" align="center">SVN</td>
</tr>
+ <tr> <!-- from Issaquah -->
+ <td><a href="http://wg21.link/p0512r0">P0512R0</a></td>
+ </tr>
<tr>
<td>Non-type template parameters with <tt>auto</tt> type</td>
<td><a href="http://wg21.link/p0127r2">P0127R2</a></td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr>
<td>Guaranteed copy elision</td>
<td><a href="http://wg21.link/p0135r1">P0135R1</a></td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr>
<td rowspan=2>Stricter expression evaluation order</td>
<td><a href="http://wg21.link/p0145r3">P0145R3</a></td>
- <td class="svn" align="center" rowspan=2>Clang 4 <a href="#p0145">(10)</a></td>
+ <td class="full" align="center" rowspan=2>Clang 4 <a href="#p0145">(10)</a></td>
</tr>
<tr>
<td><a href="http://wg21.link/p0400r0">P0400R0</a></td>
@@ -722,7 +725,7 @@ as the draft C++1z standard evolves.
<tr>
<td>Structured bindings</td>
<td><a href="http://wg21.link/p0217r3">P0217R3</a></td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr>
<td>Separate variable and condition for <tt>if</tt> and <tt>switch</tt></td>
@@ -738,12 +741,12 @@ as the draft C++1z standard evolves.
<tr>
<td>Removing deprecated dynamic exception specifications</td>
<td><a href="http://wg21.link/p0003r5">P0003R5</a></td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr>
<td>Pack expansions in <em>using-declarations</em></td>
<td><a href="http://wg21.link/p0195r2">P0195R2</a></td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
</table>